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