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