1 /**
2 * Copyright (c) 2021 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 "emitter.h"
17
18 #include <binder/binder.h>
19 #include <binder/scope.h>
20 #include <binder/variable.h>
21 #include <compiler/base/literals.h>
22 #include <compiler/core/compilerContext.h>
23 #include <compiler/core/emitter/typeExtractorEmitter.h>
24 #include <compiler/core/pandagen.h>
25 #include <compiler/debugger/debuginfoDumper.h>
26 #include <compiler/base/catchTable.h>
27 #include <es2panda.h>
28 #include <gen/isa.h>
29 #include <ir/base/methodDefinition.h>
30 #include <ir/base/scriptFunction.h>
31 #include <ir/expressions/functionExpression.h>
32 #include <ir/expressions/literal.h>
33 #include <ir/statements/blockStatement.h>
34 #include <macros.h>
35 #include <parser/program/program.h>
36 #include <util/helpers.h>
37
38 #include <string>
39 #include <string_view>
40 #include <tuple>
41 #include <utility>
42
43 namespace panda::es2panda::compiler {
44 constexpr const auto LANG_EXT = panda::pandasm::extensions::Language::ECMASCRIPT;
45
FunctionEmitter(ArenaAllocator * allocator,const PandaGen * pg)46 FunctionEmitter::FunctionEmitter(ArenaAllocator *allocator, const PandaGen *pg)
47 : pg_(pg), literalBuffers_(allocator->Adapter())
48 {
49 func_ = allocator->New<panda::pandasm::Function>(pg->InternalName().Mutf8(), LANG_EXT);
50
51 size_t paramCount = pg->InternalParamCount();
52 func_->params.reserve(paramCount);
53
54 for (uint32_t i = 0; i < paramCount; ++i) {
55 func_->params.emplace_back(panda::pandasm::Type("any", 0), LANG_EXT);
56 }
57
58 func_->regs_num = pg->TotalRegsNum();
59 func_->return_type = panda::pandasm::Type("any", 0);
60 }
61
Generate(util::PatchFix * patchFixHelper)62 void FunctionEmitter::Generate(util::PatchFix *patchFixHelper)
63 {
64 GenFunctionKind();
65 GenIcSize();
66 GenFunctionInstructions();
67 GenVariablesDebugInfo();
68 GenSourceFileDebugInfo();
69 GenFunctionCatchTables();
70 GenLiteralBuffers();
71 GenFunctionSource();
72 GenConcurrentFunctionModuleRequests();
73 if (patchFixHelper != nullptr) {
74 patchFixHelper->ProcessFunction(pg_, func_, literalBuffers_);
75 }
76 }
77
Strings() const78 const ArenaSet<util::StringView> &FunctionEmitter::Strings() const
79 {
80 return pg_->Strings();
81 }
82
GenFunctionKind()83 void FunctionEmitter::GenFunctionKind()
84 {
85 func_->SetFunctionKind(static_cast<panda::panda_file::FunctionKind>(pg_->GetFunctionKind()));
86 }
87
GenIcSize()88 void FunctionEmitter::GenIcSize()
89 {
90 func_->SetSlotsNum(pg_->GetCurrentSlot());
91 }
92
GenBufferLiterals(const LiteralBuffer * buff)93 void FunctionEmitter::GenBufferLiterals(const LiteralBuffer *buff)
94 {
95 Emitter::GenBufferLiterals(literalBuffers_, buff);
96 }
97
SourceCode() const98 util::StringView FunctionEmitter::SourceCode() const
99 {
100 if (pg_->RootNode()->IsProgram()) {
101 return pg_->Binder()->Program()->SourceCode();
102 }
103 return static_cast<const ir::ScriptFunction *>(pg_->RootNode())->SourceCode(pg_->Binder());
104 }
105
GetLineIndex() const106 lexer::LineIndex &FunctionEmitter::GetLineIndex() const
107 {
108 return const_cast<lexer::LineIndex &>(pg_->Binder()->Program()->GetLineIndex());
109 }
110
MatchFormat(const IRNode * node,const Formats & formats)111 static Format MatchFormat(const IRNode *node, const Formats &formats)
112 {
113 std::array<const VReg *, IRNode::MAX_REG_OPERAND> regs {};
114 auto regCnt = node->Registers(®s);
115 auto registers = Span<const VReg *>(regs.data(), regs.data() + regCnt);
116
117 const auto *iter = formats.begin();
118
119 for (; iter != formats.end(); iter++) {
120 auto format = *iter;
121 size_t limit = 0;
122 for (const auto &formatItem : format.GetFormatItem()) {
123 if (formatItem.IsVReg()) {
124 limit = 1 << formatItem.Bitwidth();
125 break;
126 }
127 }
128
129 if (std::all_of(registers.begin(), registers.end(), [limit](const VReg *reg) { return *reg < limit; })) {
130 return format;
131 }
132 }
133
134 UNREACHABLE();
135 return *iter;
136 }
137
GetIRNodeWholeLength(const IRNode * node)138 static size_t GetIRNodeWholeLength(const IRNode *node)
139 {
140 Formats formats = node->GetFormats();
141 if (formats.empty()) {
142 return 0;
143 }
144
145 size_t len = 1;
146 constexpr size_t BIT_WIDTH = 8;
147 const auto format = MatchFormat(node, formats);
148
149 for (auto fi : format.GetFormatItem()) {
150 len += fi.Bitwidth() / BIT_WIDTH;
151 }
152
153 return len;
154 }
155
WholeLine(const util::StringView & source,lexer::SourceRange range)156 [[maybe_unused]] static std::string WholeLine(const util::StringView &source, lexer::SourceRange range)
157 {
158 return source.Substr(range.start.index, range.end.index).EscapeSymbol<util::StringView::Mutf8Encode>();
159 }
160
161 // This is for supporting setting breakpoint on the right parenthesis of a scriptFunciton.
UpdateForReturnIns(const ir::AstNode * astNode,panda::pandasm::Ins * pandaIns)162 uint32_t FunctionEmitter::UpdateForReturnIns(const ir::AstNode *astNode, panda::pandasm::Ins *pandaIns)
163 {
164 constexpr size_t INVALID_LINE = -1;
165 constexpr uint32_t INVALID_COL = -1;
166 // The GetLocation method calculated position starts with 1, and
167 // the column number in pandaIns->ins_debug starts with 0
168 constexpr uint32_t OFFSET_COL = 1;
169 uint32_t columnNum = INVALID_COL;
170 if (pandaIns->opcode == pandasm::Opcode::RETURNUNDEFINED || pandaIns->opcode == pandasm::Opcode::RETURN) {
171 while (astNode != nullptr && !astNode->IsScriptFunction()) {
172 if (astNode->IsBlockStatement() && astNode->AsBlockStatement()->Scope()->Node()->IsScriptFunction()) {
173 astNode = astNode->AsBlockStatement()->Scope()->Node();
174 break;
175 }
176 astNode = astNode->Parent();
177 }
178 pandaIns->ins_debug.line_number = astNode ? astNode->Range().end.line : INVALID_LINE;
179 columnNum = astNode ? (GetLineIndex().GetLocation(astNode->Range().end).col - OFFSET_COL) : INVALID_COL;
180 } else {
181 pandaIns->ins_debug.line_number = astNode ? astNode->Range().start.line : INVALID_LINE;
182 columnNum = astNode ? (GetLineIndex().GetLocation(astNode->Range().start).col - OFFSET_COL) : INVALID_COL;
183 }
184 return columnNum;
185 }
186
GenInstructionDebugInfo(const IRNode * ins,panda::pandasm::Ins * pandaIns)187 void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns)
188 {
189 const ir::AstNode *astNode = ins->Node();
190 if (astNode == FIRST_NODE_OF_FUNCTION) {
191 astNode = pg_->Debuginfo().firstStmt;
192 if (!astNode) {
193 return;
194 }
195 }
196 uint32_t columnNum = UpdateForReturnIns(astNode, pandaIns);
197
198 if (pg_->IsDebug()) {
199 size_t insLen = GetIRNodeWholeLength(ins);
200 if (insLen != 0) {
201 pandaIns->ins_debug.bound_left = offset_;
202 pandaIns->ins_debug.bound_right = offset_ + insLen;
203 }
204
205 offset_ += insLen;
206 pandaIns->ins_debug.column_number = columnNum;
207 }
208 }
209
GenFunctionInstructions()210 void FunctionEmitter::GenFunctionInstructions()
211 {
212 func_->ins.reserve(pg_->Insns().size());
213
214 for (const auto *ins : pg_->Insns()) {
215 auto &pandaIns = func_->ins.emplace_back();
216
217 ins->Transform(&pandaIns);
218 GenInstructionDebugInfo(ins, &pandaIns);
219 }
220
221 if (pg_->Context()->IsTypeExtractorEnabled()) {
222 TypeExtractorEmitter(pg_, func_);
223 }
224 }
225
GenFunctionCatchTables()226 void FunctionEmitter::GenFunctionCatchTables()
227 {
228 func_->catch_blocks.reserve(pg_->CatchList().size());
229
230 for (const auto *catchBlock : pg_->CatchList()) {
231 const auto &labelSet = catchBlock->LabelSet();
232
233 auto &pandaCatchBlock = func_->catch_blocks.emplace_back();
234 pandaCatchBlock.try_begin_label = labelSet.TryBegin()->Id();
235 pandaCatchBlock.try_end_label = labelSet.TryEnd()->Id();
236 pandaCatchBlock.catch_begin_label = labelSet.CatchBegin()->Id();
237 pandaCatchBlock.catch_end_label = labelSet.CatchEnd()->Id();
238 }
239 }
240
GenLiteralBuffers()241 void FunctionEmitter::GenLiteralBuffers()
242 {
243 for (const auto *buff : pg_->BuffStorage()) {
244 GenBufferLiterals(buff);
245 }
246 }
247
GenSourceFileDebugInfo()248 void FunctionEmitter::GenSourceFileDebugInfo()
249 {
250 if (pg_->SourceFile().empty()) {
251 func_->source_file = std::string {pg_->Binder()->Program()->SourceFile()};
252 } else {
253 func_->source_file = pg_->SourceFile();
254 }
255
256 if (!pg_->IsDebug()) {
257 return;
258 }
259
260 if (pg_->RootNode()->IsProgram()) {
261 func_->source_code = SourceCode().Mutf8();
262 }
263 }
264
GenFunctionSource()265 void FunctionEmitter::GenFunctionSource()
266 {
267 if (pg_->RootNode()->IsProgram()) {
268 return;
269 }
270
271 if (pg_->Context()->IsRecordSource() || (static_cast<const ir::ScriptFunction *>(pg_->RootNode()))->ShowSource()) {
272 func_->source_code = SourceCode().Mutf8();
273 }
274 }
275
GenScopeVariableInfo(const binder::Scope * scope)276 void FunctionEmitter::GenScopeVariableInfo(const binder::Scope *scope)
277 {
278 const auto *startIns = scope->ScopeStart();
279 const auto *endIns = scope->ScopeEnd();
280
281 uint32_t start = 0;
282 uint32_t count = 0;
283
284 for (const auto *it : pg_->Insns()) {
285 if (startIns == it) {
286 start = count;
287 } else if (endIns == it) {
288 auto varsLength = static_cast<uint32_t>(count - start + 1);
289
290 for (const auto &[name, variable] : scope->Bindings()) {
291 if (!variable->IsLocalVariable() || variable->LexicalBound()) {
292 continue;
293 }
294
295 auto &variableDebug = func_->local_variable_debug.emplace_back();
296 variableDebug.name = name.Mutf8();
297 variableDebug.signature = "any";
298 variableDebug.signature_type = "any";
299 // Register spill causes an offset being applied to all registers in all instructions (refer to
300 // RegAllocator::AdjustInsRegWhenHasSpill for more details). Therefore, we also add this offset
301 // to the variable-to-register mapping before dumping it to the debug information of the abc file
302 // (the following code).
303 // We do not correct the original variable mapping in the scope object since it is not used after
304 // the register spill phase, while we do not know the number of spilled registers before that phase.
305 // If any future modifications require access to the variable mapping after the register spill,
306 // please correct the mapping first and remove the offset increment operation in the following code.
307 variableDebug.reg =
308 static_cast<int32_t>(variable->AsLocalVariable()->Vreg()) + pg_->GetSpillRegsCount();
309 variableDebug.start = start;
310 variableDebug.length = static_cast<uint32_t>(varsLength);
311 }
312
313 break;
314 }
315
316 count++;
317 }
318 }
319
GenVariablesDebugInfo()320 void FunctionEmitter::GenVariablesDebugInfo()
321 {
322 if (!pg_->IsDebug()) {
323 return;
324 }
325
326 for (const auto *scope : pg_->Debuginfo().variableDebugInfo) {
327 GenScopeVariableInfo(scope);
328 }
329 }
330
GenConcurrentFunctionModuleRequests()331 void FunctionEmitter::GenConcurrentFunctionModuleRequests()
332 {
333 if (static_cast<panda::panda_file::FunctionKind>(pg_->GetFunctionKind()) !=
334 panda::panda_file::FunctionKind::CONCURRENT_FUNCTION) {
335 return;
336 }
337
338 std::vector<int> moduleRequests =
339 static_cast<const ir::ScriptFunction *>(pg_->RootNode())->GetConcurrentModuleRequests();
340 func_->concurrent_module_requests.reserve(moduleRequests.size());
341 for (auto it : moduleRequests) {
342 func_->concurrent_module_requests.emplace_back(it);
343 }
344 }
345
346 // Emitter
347
Emitter(const CompilerContext * context)348 Emitter::Emitter(const CompilerContext *context)
349 {
350 prog_ = new panda::pandasm::Program();
351 prog_->lang = LANG_EXT;
352
353 if (context->IsJsonInputFile()) {
354 GenJsonContentRecord(context);
355 return;
356 }
357
358 GenESTypeAnnotationRecord();
359 if (context->IsMergeAbc()) {
360 auto recordName = context->Binder()->Program()->FormatedRecordName().Mutf8();
361 rec_ = new panda::pandasm::Record(recordName.substr(0, recordName.find_last_of('.')), LANG_EXT);
362 SetPkgNameField(context->PkgName());
363 SetCommonjsField(context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS);
364 } else {
365 rec_ = nullptr;
366 if (context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS) {
367 GenCommonjsRecord();
368 }
369 }
370 if (context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE) {
371 AddHasTopLevelAwaitRecord(context->Binder()->Program()->HasTLA(), context);
372 }
373 }
374
~Emitter()375 Emitter::~Emitter()
376 {
377 delete prog_;
378 }
379
SetPkgNameField(std::string pkgName)380 void Emitter::SetPkgNameField(std::string pkgName)
381 {
382 auto pkgNameField = panda::pandasm::Field(LANG_EXT);
383 pkgNameField.name = "pkgName@" + pkgName;
384 pkgNameField.type = panda::pandasm::Type("u8", 0);
385 pkgNameField.metadata->SetValue(
386 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(0)));
387 rec_->field_list.emplace_back(std::move(pkgNameField));
388 }
389
GenRecordNameInfo() const390 void Emitter::GenRecordNameInfo() const
391 {
392 if (rec_) {
393 prog_->record_table.emplace(rec_->name, std::move(*rec_));
394 }
395 }
396
GenTypeInfoRecord() const397 void Emitter::GenTypeInfoRecord() const
398 {
399 auto typeInfoRecord = panda::pandasm::Record(TypeExtractorEmitter::TYPE_INFO_RECORD, LANG_EXT);
400 typeInfoRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
401 prog_->record_table.emplace(typeInfoRecord.name, std::move(typeInfoRecord));
402 }
403
GenESTypeAnnotationRecord() const404 void Emitter::GenESTypeAnnotationRecord() const
405 {
406 auto typeAnnotationRecord = panda::pandasm::Record(TypeExtractorEmitter::TYPE_ANNOTATION, LANG_EXT);
407 typeAnnotationRecord.metadata->SetAttribute("external");
408 typeAnnotationRecord.metadata->SetAccessFlags(panda::ACC_ANNOTATION);
409 prog_->record_table.emplace(typeAnnotationRecord.name, std::move(typeAnnotationRecord));
410 }
411
GenJsonContentRecord(const CompilerContext * context)412 void Emitter::GenJsonContentRecord(const CompilerContext *context)
413 {
414 rec_ = new panda::pandasm::Record(std::string(context->RecordName()), panda::panda_file::SourceLang::ECMASCRIPT);
415 auto jsonContentField = panda::pandasm::Field(panda::panda_file::SourceLang::ECMASCRIPT);
416 jsonContentField.name = "jsonFileContent";
417 jsonContentField.type = panda::pandasm::Type("u32", 0);
418 jsonContentField.metadata->SetValue(panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::STRING>(
419 static_cast<std::string_view>(context->SourceFile())));
420 rec_->field_list.emplace_back(std::move(jsonContentField));
421 if (context->PatchFixHelper()) {
422 context->PatchFixHelper()->ProcessJsonContentRecord(rec_->name, context->SourceFile());
423 }
424 }
425
AddFunction(FunctionEmitter * func,CompilerContext * context)426 void Emitter::AddFunction(FunctionEmitter *func, CompilerContext *context)
427 {
428 std::lock_guard<std::mutex> lock(m_);
429
430 for (const auto &str : func->Strings()) {
431 prog_->strings.insert(str.Mutf8());
432 }
433
434 for (auto &[idx, buf] : func->LiteralBuffers()) {
435 auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(buf));
436 auto litId = std::string(context->Binder()->Program()->RecordName()) + "_" + std::to_string(idx);
437 prog_->literalarray_table.emplace(litId, std::move(literalArrayInstance));
438 }
439
440 auto *function = func->Function();
441 prog_->function_table.emplace(function->name, std::move(*function));
442 }
443
AddSourceTextModuleRecord(ModuleRecordEmitter * module,CompilerContext * context)444 void Emitter::AddSourceTextModuleRecord(ModuleRecordEmitter *module, CompilerContext *context)
445 {
446 std::lock_guard<std::mutex> lock(m_);
447
448 auto moduleLiteral = std::string(context->Binder()->Program()->RecordName()) + "_" +
449 std::to_string(module->Index());
450 if (context->IsMergeAbc()) {
451 auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
452 moduleIdxField.name = "moduleRecordIdx";
453 moduleIdxField.type = panda::pandasm::Type("u32", 0);
454 moduleIdxField.metadata->SetValue(
455 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
456 static_cast<std::string_view>(moduleLiteral)));
457 rec_->field_list.emplace_back(std::move(moduleIdxField));
458
459 if (context->PatchFixHelper()) {
460 context->PatchFixHelper()->ProcessModule(rec_->name, module->Buffer());
461 }
462 } else {
463 auto ecmaModuleRecord = panda::pandasm::Record("_ESModuleRecord", LANG_EXT);
464 ecmaModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
465
466 auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
467 moduleIdxField.name = std::string {context->Binder()->Program()->SourceFile()};
468 moduleIdxField.type = panda::pandasm::Type("u32", 0);
469 moduleIdxField.metadata->SetValue(
470 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
471 static_cast<std::string_view>(moduleLiteral)));
472 ecmaModuleRecord.field_list.emplace_back(std::move(moduleIdxField));
473
474 if (context->PatchFixHelper()) {
475 context->PatchFixHelper()->ProcessModule(ecmaModuleRecord.name, module->Buffer());
476 }
477 prog_->record_table.emplace(ecmaModuleRecord.name, std::move(ecmaModuleRecord));
478 }
479 auto &moduleLiteralsBuffer = module->Buffer();
480 auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(moduleLiteralsBuffer));
481 prog_->literalarray_table.emplace(static_cast<std::string_view>(moduleLiteral), std::move(literalArrayInstance));
482 }
483
AddHasTopLevelAwaitRecord(bool hasTLA,const CompilerContext * context)484 void Emitter::AddHasTopLevelAwaitRecord(bool hasTLA, const CompilerContext *context)
485 {
486 if (context->IsMergeAbc()) {
487 auto hasTLAField = panda::pandasm::Field(LANG_EXT);
488 hasTLAField.name = "hasTopLevelAwait";
489 hasTLAField.type = panda::pandasm::Type("u8", 0);
490 hasTLAField.metadata->SetValue(
491 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(hasTLA))
492 );
493 rec_->field_list.emplace_back(std::move(hasTLAField));
494 } else if (hasTLA) {
495 auto hasTLARecord = panda::pandasm::Record("_HasTopLevelAwait", LANG_EXT);
496 hasTLARecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
497 auto hasTLAField = panda::pandasm::Field(LANG_EXT);
498 hasTLAField.name = "hasTopLevelAwait";
499 hasTLAField.type = panda::pandasm::Type("u8", 0);
500 hasTLAField.metadata->SetValue(
501 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(true))
502 );
503 hasTLARecord.field_list.emplace_back(std::move(hasTLAField));
504
505 prog_->record_table.emplace(hasTLARecord.name, std::move(hasTLARecord));
506 }
507 }
508
FillTypeInfoRecord(CompilerContext * context,bool typeFlag,int64_t typeSummaryIndex,const std::string & recordName) const509 void Emitter::FillTypeInfoRecord(CompilerContext *context, bool typeFlag, int64_t typeSummaryIndex,
510 const std::string &recordName) const
511 {
512 if (!context->IsMergeAbc()) {
513 TypeExtractorEmitter::GenTypeInfoRecord(prog_, typeFlag, typeSummaryIndex, recordName);
514 } else {
515 TypeExtractorEmitter::GenTypeInfoRecordForMergeABC(prog_, typeFlag, typeSummaryIndex, recordName);
516 }
517 }
518
FillTypeLiteralBuffers(const extractor::TypeRecorder * recorder) const519 void Emitter::FillTypeLiteralBuffers(const extractor::TypeRecorder *recorder) const
520 {
521 TypeExtractorEmitter::GenTypeLiteralBuffers(prog_, recorder);
522 }
523
524 // static
GenBufferLiterals(ArenaVector<std::pair<int32_t,std::vector<Literal>>> & literalBuffers,const LiteralBuffer * buff)525 void Emitter::GenBufferLiterals(ArenaVector<std::pair<int32_t, std::vector<Literal>>> &literalBuffers,
526 const LiteralBuffer *buff)
527 {
528 auto &[idx, array] = literalBuffers.emplace_back();
529 idx = buff->Index();
530 constexpr size_t ARRAY_EXPANSION = 2;
531 array.reserve(buff->Literals().size() * ARRAY_EXPANSION);
532
533 for (const auto *literal : buff->Literals()) {
534 panda::pandasm::LiteralArray::Literal valueLit;
535 panda::pandasm::LiteralArray::Literal tagLit;
536
537 ir::LiteralTag tag = literal->Tag();
538
539 switch (tag) {
540 case ir::LiteralTag::BOOLEAN: {
541 valueLit.tag_ = panda::panda_file::LiteralTag::BOOL;
542 valueLit.value_ = literal->GetBoolean();
543 break;
544 }
545 case ir::LiteralTag::INTEGER: {
546 valueLit.tag_ = panda::panda_file::LiteralTag::INTEGER;
547 valueLit.value_ = literal->GetInt();
548 break;
549 }
550 case ir::LiteralTag::DOUBLE: {
551 valueLit.tag_ = panda::panda_file::LiteralTag::DOUBLE;
552 valueLit.value_ = literal->GetDouble();
553 break;
554 }
555 case ir::LiteralTag::STRING: {
556 valueLit.tag_ = panda::panda_file::LiteralTag::STRING;
557 valueLit.value_ = literal->GetString().Mutf8();
558 break;
559 }
560 case ir::LiteralTag::ACCESSOR: {
561 valueLit.tag_ = panda::panda_file::LiteralTag::ACCESSOR;
562 valueLit.value_ = static_cast<uint8_t>(0);
563 break;
564 }
565 case ir::LiteralTag::METHOD: {
566 valueLit.tag_ = panda::panda_file::LiteralTag::METHOD;
567 valueLit.value_ = literal->GetMethod().Mutf8();
568 break;
569 }
570 case ir::LiteralTag::METHODAFFILIATE: {
571 valueLit.tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE;
572 valueLit.value_ = literal->GetMethodAffiliate();
573 break;
574 }
575 case ir::LiteralTag::GENERATOR_METHOD: {
576 valueLit.tag_ = panda::panda_file::LiteralTag::GENERATORMETHOD;
577 valueLit.value_ = literal->GetMethod().Mutf8();
578 break;
579 }
580 case ir::LiteralTag::LITERALBUFFERINDEX: {
581 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALBUFFERINDEX;
582 valueLit.value_ = literal->GetInt();
583 break;
584 }
585 case ir::LiteralTag::LITERALARRAY: {
586 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALARRAY;
587 valueLit.value_ = literal->GetString().Mutf8();
588 break;
589 }
590 case ir::LiteralTag::BUILTINTYPEINDEX: {
591 valueLit.tag_ = panda::panda_file::LiteralTag::BUILTINTYPEINDEX;
592 valueLit.value_ = static_cast<uint8_t>(literal->GetInt());
593 break;
594 }
595 case ir::LiteralTag::GETTER: {
596 valueLit.tag_ = panda::panda_file::LiteralTag::GETTER;
597 valueLit.value_ = literal->GetMethod().Mutf8();
598 break;
599 }
600 case ir::LiteralTag::SETTER: {
601 valueLit.tag_ = panda::panda_file::LiteralTag::SETTER;
602 valueLit.value_ = literal->GetMethod().Mutf8();
603 break;
604 }
605 // TODO: support ir::LiteralTag::ASYNC_GENERATOR_METHOD
606 case ir::LiteralTag::NULL_VALUE: {
607 valueLit.tag_ = panda::panda_file::LiteralTag::NULLVALUE;
608 valueLit.value_ = static_cast<uint8_t>(0);
609 break;
610 }
611 default:
612 break;
613 }
614
615 tagLit.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
616 tagLit.value_ = static_cast<uint8_t>(valueLit.tag_);
617
618 array.emplace_back(tagLit);
619 array.emplace_back(valueLit);
620 }
621 }
622
DumpAsm(const panda::pandasm::Program * prog)623 void Emitter::DumpAsm(const panda::pandasm::Program *prog)
624 {
625 auto &ss = std::cout;
626
627 ss << ".language ECMAScript" << std::endl << std::endl;
628
629 for (auto &[name, func] : prog->function_table) {
630 ss << ".function any " << name << '(';
631
632 for (uint32_t i = 0; i < func.GetParamsNum(); i++) {
633 ss << "any a" << std::to_string(i);
634
635 if (i != func.GetParamsNum() - 1) {
636 ss << ", ";
637 }
638 }
639
640 ss << ") {" << std::endl;
641
642 for (const auto &ins : func.ins) {
643 ss << (ins.set_label ? "" : "\t") << ins.ToString("", true, func.GetTotalRegs()) << std::endl;
644 }
645
646 ss << "}" << std::endl << std::endl;
647
648 for (const auto &ct : func.catch_blocks) {
649 ss << ".catchall " << ct.try_begin_label << ", " << ct.try_end_label << ", " << ct.catch_begin_label
650 << std::endl
651 << std::endl;
652 }
653 }
654
655 ss << std::endl;
656 }
657
Finalize(bool dumpDebugInfo,util::PatchFix * patchFixHelper)658 panda::pandasm::Program *Emitter::Finalize(bool dumpDebugInfo, util::PatchFix *patchFixHelper)
659 {
660 if (dumpDebugInfo) {
661 debuginfo::DebugInfoDumper dumper(prog_);
662 dumper.Dump();
663 }
664
665 if (rec_) {
666 delete rec_;
667 rec_ = nullptr;
668 }
669
670 if (patchFixHelper) {
671 patchFixHelper->Finalize(&prog_);
672 }
673
674 auto *prog = prog_;
675 prog_ = nullptr;
676 return prog;
677 }
678
GetProgram() const679 panda::pandasm::Program *Emitter::GetProgram() const
680 {
681 return prog_;
682 }
683
684 } // namespace panda::es2panda::compiler
685