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/annotation.h>
29 #include <ir/base/classDefinition.h>
30 #include <ir/base/methodDefinition.h>
31 #include <ir/base/property.h>
32 #include <ir/base/scriptFunction.h>
33 #include <ir/expressions/arrayExpression.h>
34 #include <ir/expressions/callExpression.h>
35 #include <ir/expressions/functionExpression.h>
36 #include <ir/expressions/literal.h>
37 #include <ir/expressions/literals/booleanLiteral.h>
38 #include <ir/expressions/literals/numberLiteral.h>
39 #include <ir/expressions/literals/stringLiteral.h>
40 #include <ir/expressions/newExpression.h>
41 #include <ir/expressions/unaryExpression.h>
42 #include <ir/expressions/objectExpression.h>
43 #include <ir/statements/blockStatement.h>
44 #include <ir/statements/classDeclaration.h>
45 #include <ir/ts/tsArrayType.h>
46 #include <ir/ts/tsEnumMember.h>
47 #include <ir/ts/tsTypeParameterInstantiation.h>
48 #include <ir/ts/tsTypeReference.h>
49 #include <macros.h>
50 #include <parser/program/program.h>
51 #include <util/helpers.h>
52
53 #include <string>
54 #include <string_view>
55 #include <tuple>
56 #include <utility>
57
58 namespace panda::es2panda::compiler {
59 constexpr const auto LANG_EXT = panda::pandasm::extensions::Language::ECMASCRIPT;
60
FunctionEmitter(ArenaAllocator *allocator, const PandaGen *pg)61 FunctionEmitter::FunctionEmitter(ArenaAllocator *allocator, const PandaGen *pg)
62 : pg_(pg),
63 literalBuffers_(allocator->Adapter()),
64 literalArrays_(allocator->Adapter()),
65 externalAnnotationRecords_(allocator->Adapter())
66 {
67 func_ = allocator->New<panda::pandasm::Function>(pg->InternalName().Mutf8(), LANG_EXT);
68 CHECK_NOT_NULL(func_);
69
70 size_t paramCount = pg->InternalParamCount();
71 func_->params.reserve(paramCount);
72
73 for (uint32_t i = 0; i < paramCount; ++i) {
74 func_->params.emplace_back(panda::pandasm::Type("any", 0), LANG_EXT);
75 }
76
77 func_->regs_num = pg->TotalRegsNum();
78 func_->return_type = panda::pandasm::Type("any", 0);
79 }
80
Generate(util::PatchFix *patchFixHelper)81 void FunctionEmitter::Generate(util::PatchFix *patchFixHelper)
82 {
83 GenFunctionKind();
84 GenIcSize();
85 GenFunctionInstructions();
86 GenVariablesDebugInfo();
87 GenSourceFileDebugInfo();
88 GenFunctionCatchTables();
89 GenLiteralBuffers();
90 GenConcurrentFunctionModuleRequests();
91 GenAnnotations();
92 if (patchFixHelper != nullptr) {
93 patchFixHelper->ProcessFunction(pg_, func_, literalBuffers_);
94 }
95 }
96
Strings() const97 const ArenaSet<util::StringView> &FunctionEmitter::Strings() const
98 {
99 return pg_->Strings();
100 }
101
GenFunctionKind()102 void FunctionEmitter::GenFunctionKind()
103 {
104 func_->SetFunctionKind(static_cast<panda::panda_file::FunctionKind>(pg_->GetFunctionKind()));
105 }
106
GenIcSize()107 void FunctionEmitter::GenIcSize()
108 {
109 func_->SetSlotsNum(pg_->GetCurrentSlot());
110 }
111
GenBufferLiterals(const LiteralBuffer *buff)112 void FunctionEmitter::GenBufferLiterals(const LiteralBuffer *buff)
113 {
114 Emitter::GenBufferLiterals(literalBuffers_, buff);
115 }
116
SourceCode() const117 util::StringView FunctionEmitter::SourceCode() const
118 {
119 if (pg_->RootNode()->IsProgram()) {
120 return pg_->Binder()->Program()->SourceCode();
121 }
122 return static_cast<const ir::ScriptFunction *>(pg_->RootNode())->SourceCode(pg_->Binder());
123 }
124
GetLineIndex() const125 lexer::LineIndex &FunctionEmitter::GetLineIndex() const
126 {
127 return const_cast<lexer::LineIndex &>(pg_->Binder()->Program()->GetLineIndex());
128 }
129
MatchFormat(const IRNode *node, const Formats &formats)130 static Format MatchFormat(const IRNode *node, const Formats &formats)
131 {
132 std::array<const VReg *, IRNode::MAX_REG_OPERAND> regs {};
133 auto regCnt = node->Registers(®s);
134 auto registers = Span<const VReg *>(regs.data(), regs.data() + regCnt);
135
136 const auto *iter = formats.begin();
137
138 for (; iter != formats.end(); iter++) {
139 auto format = *iter;
140 size_t limit = 0;
141 for (const auto &formatItem : format.GetFormatItem()) {
142 if (formatItem.IsVReg()) {
143 limit = 1 << formatItem.Bitwidth();
144 break;
145 }
146 }
147
148 if (std::all_of(registers.begin(), registers.end(), [limit](const VReg *reg) { return *reg < limit; })) {
149 return format;
150 }
151 }
152
153 UNREACHABLE();
154 return *iter;
155 }
156
GetIRNodeWholeLength(const IRNode *node)157 static size_t GetIRNodeWholeLength(const IRNode *node)
158 {
159 Formats formats = node->GetFormats();
160 if (formats.empty()) {
161 return 0;
162 }
163
164 size_t len = 1;
165 constexpr size_t BIT_WIDTH = 8;
166 const auto format = MatchFormat(node, formats);
167
168 for (auto fi : format.GetFormatItem()) {
169 len += fi.Bitwidth() / BIT_WIDTH;
170 }
171
172 return len;
173 }
174
WholeLine(const util::StringView &source, lexer::SourceRange range)175 [[maybe_unused]] static std::string WholeLine(const util::StringView &source, lexer::SourceRange range)
176 {
177 return source.Substr(range.start.index, range.end.index).EscapeSymbol<util::StringView::Mutf8Encode>();
178 }
179
180 // This is for supporting setting breakpoint on the right parenthesis of a scriptFunciton.
UpdateForReturnIns(const ir::AstNode *astNode, panda::pandasm::Ins *pandaIns)181 uint32_t FunctionEmitter::UpdateForReturnIns(const ir::AstNode *astNode, panda::pandasm::Ins *pandaIns)
182 {
183 constexpr size_t INVALID_LINE = -1;
184 constexpr uint32_t INVALID_COL = -1;
185 // The GetLocation method calculated position starts with 1, and
186 // the column number in pandaIns->ins_debug starts with 0
187 constexpr uint32_t OFFSET_COL = 1;
188 uint32_t columnNum = INVALID_COL;
189 if (pandaIns->opcode == pandasm::Opcode::RETURNUNDEFINED || pandaIns->opcode == pandasm::Opcode::RETURN) {
190 while (astNode != nullptr && !astNode->IsScriptFunction()) {
191 if (astNode->IsBlockStatement() &&
192 astNode->AsBlockStatement()->Scope() &&
193 astNode->AsBlockStatement()->Scope()->Node() &&
194 astNode->AsBlockStatement()->Scope()->Node()->IsScriptFunction()) {
195 astNode = astNode->AsBlockStatement()->Scope()->Node();
196 break;
197 }
198 astNode = astNode->Parent();
199 }
200 pandaIns->ins_debug.line_number = astNode ? astNode->Range().end.line : INVALID_LINE;
201 columnNum = astNode ? (GetLineIndex().GetLocation(astNode->Range().end).col - OFFSET_COL) : INVALID_COL;
202 } else {
203 pandaIns->ins_debug.line_number = astNode ? astNode->Range().start.line : INVALID_LINE;
204 columnNum = astNode ? (GetLineIndex().GetLocation(astNode->Range().start).col - OFFSET_COL) : INVALID_COL;
205 }
206 return columnNum;
207 }
208
GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns)209 void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns)
210 {
211 const ir::AstNode *astNode = ins->Node();
212 if (astNode == FIRST_NODE_OF_FUNCTION) {
213 astNode = pg_->Debuginfo().firstStmt;
214 if (!astNode) {
215 return;
216 }
217 }
218 uint32_t columnNum = UpdateForReturnIns(astNode, pandaIns);
219
220 if (pg_->IsDebug()) {
221 size_t insLen = GetIRNodeWholeLength(ins);
222 if (insLen != 0) {
223 pandaIns->ins_debug.bound_left = offset_;
224 pandaIns->ins_debug.bound_right = offset_ + insLen;
225 }
226
227 offset_ += insLen;
228 pandaIns->ins_debug.column_number = columnNum;
229 }
230 }
231
ProcessNewExpressionInLiteralArray( const ir::Expression *array)232 static std::vector<panda::pandasm::LiteralArray::Literal> ProcessNewExpressionInLiteralArray(
233 const ir::Expression *array)
234 {
235 std::vector<panda::pandasm::LiteralArray::Literal> literals;
236
237 const auto &typeParams = array->AsNewExpression()->TypeParams()->Params();
238 auto type = typeParams[0]->Type();
239 literals.emplace_back(
240 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::TAGVALUE,
241 static_cast<uint8_t>(panda::panda_file::LiteralTag::BUILTINTYPEINDEX)});
242 switch (type) {
243 case ir::AstNodeType::TS_NUMBER_KEYWORD: {
244 literals.emplace_back(pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::BUILTINTYPEINDEX,
245 ir::Annotation::EMPTY_LITERAL_ARRAY_WITH_NUMBER_TYPE});
246 break;
247 }
248 case ir::AstNodeType::TS_BOOLEAN_KEYWORD: {
249 literals.emplace_back(pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::BUILTINTYPEINDEX,
250 ir::Annotation::EMPTY_LITERAL_ARRAY_WITH_BOOLEAN_TYPE});
251 break;
252 }
253 case ir::AstNodeType::TS_STRING_KEYWORD: {
254 literals.emplace_back(pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::BUILTINTYPEINDEX,
255 ir::Annotation::EMPTY_LITERAL_ARRAY_WITH_STRING_TYPE});
256 break;
257 }
258 case ir::AstNodeType::TS_TYPE_REFERENCE: {
259 const auto &args = array->AsNewExpression()->Arguments();
260 uint8_t value = args[0]->AsNumberLiteral()->Number<uint8_t>();
261 if (value == ir::Annotation::ENUM_LITERAL_ARRAY_WITH_EMPTY_INITIALIZER_NUMBER_TYPE) {
262 // By convention, this is an empty array of enums with underlying number type
263 literals.emplace_back(pandasm::LiteralArray::Literal {
264 panda::panda_file::LiteralTag::BUILTINTYPEINDEX,
265 ir::Annotation::EMPTY_LITERAL_ARRAY_WITH_NUMBER_TYPE});
266 } else if (value == ir::Annotation::ENUM_LITERAL_ARRAY_WITH_EMPTY_INITIALIZER_STRING_TYPE) {
267 // By convention, this is an empty array of enums with underlying string type
268 literals.emplace_back(pandasm::LiteralArray::Literal {
269 panda::panda_file::LiteralTag::BUILTINTYPEINDEX,
270 ir::Annotation::EMPTY_LITERAL_ARRAY_WITH_STRING_TYPE});
271 } else {
272 UNREACHABLE();
273 }
274 break;
275 }
276 default:
277 UNREACHABLE();
278 }
279
280 return literals;
281 }
282
ProcessArrayExpressionInLiteralArray( const ir::Expression *array, const std::string &baseName, std::vector<std::pair<std::string, std::vector<Literal>>> &result)283 static std::vector<panda::pandasm::LiteralArray::Literal> ProcessArrayExpressionInLiteralArray(
284 const ir::Expression *array, const std::string &baseName,
285 std::vector<std::pair<std::string, std::vector<Literal>>> &result)
286 {
287 std::vector<panda::pandasm::LiteralArray::Literal> literals;
288 ArenaVector<ir::Expression *> elements {array->AsArrayExpression()->Elements()};
289
290 for (const auto *elem : elements) {
291 if (elem->IsArrayExpression() || elem->IsNewExpression()) {
292 auto litArrays = Emitter::CreateLiteralArray(elem, baseName);
293 literals.emplace_back(
294 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::TAGVALUE,
295 static_cast<uint8_t>(panda::panda_file::LiteralTag::LITERALARRAY)});
296 literals.emplace_back(pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::LITERALARRAY,
297 litArrays.back().first});
298 for (auto item : litArrays) {
299 result.push_back(item);
300 }
301 } else if (elem->IsNumberLiteral()) {
302 double doubleValue = elem->AsNumberLiteral()->Number();
303 literals.emplace_back(
304 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::TAGVALUE,
305 static_cast<uint8_t>(panda::panda_file::LiteralTag::DOUBLE)});
306 literals.emplace_back(
307 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::DOUBLE, doubleValue});
308 } else if (elem->IsBooleanLiteral()) {
309 bool boolValue = elem->AsBooleanLiteral()->Value();
310 literals.emplace_back(
311 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::TAGVALUE,
312 static_cast<uint8_t>(panda::panda_file::LiteralTag::BOOL)});
313 literals.emplace_back(pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::BOOL, boolValue});
314 } else if (elem->IsStringLiteral()) {
315 std::string stringValue {elem->AsStringLiteral()->Str().Utf8()};
316 literals.emplace_back(
317 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::TAGVALUE,
318 static_cast<uint8_t>(panda::panda_file::LiteralTag::STRING)});
319 literals.emplace_back(
320 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::STRING, stringValue});
321 } else if (elem->IsUnaryExpression()) {
322 ASSERT(elem->AsUnaryExpression()->IsNegativeNumber());
323 // In annotations other unary operators (+, !, ~) are evaluated in tsc.
324 // Only unary minus may be present in intermediate .ts
325 double doubleValue = (-1) * elem->AsUnaryExpression()->Argument()->AsNumberLiteral()->Number();
326 literals.emplace_back(
327 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::TAGVALUE,
328 static_cast<uint8_t>(panda::panda_file::LiteralTag::DOUBLE)});
329 literals.emplace_back(
330 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::DOUBLE, doubleValue});
331 } else {
332 UNREACHABLE();
333 }
334 }
335
336 return literals;
337 }
338
CreateLiteralArray(const ir::Expression *array, const std::string &baseName)339 std::vector<std::pair<std::string, std::vector<Literal>>> Emitter::CreateLiteralArray(const ir::Expression *array,
340 const std::string &baseName)
341 {
342 std::vector<std::pair<std::string, std::vector<Literal>>> result;
343 std::vector<panda::pandasm::LiteralArray::Literal> literals;
344
345 if (array->IsNewExpression()) {
346 // special case, when initializer is an empty array
347 literals = ProcessNewExpressionInLiteralArray(array);
348 } else {
349 literals = ProcessArrayExpressionInLiteralArray(array, baseName, result);
350 }
351
352 static uint32_t litArrayValueCount = 0;
353 std::string litArrayName = baseName + "_" + std::to_string(litArrayValueCount);
354 ++litArrayValueCount;
355 result.push_back(std::make_pair(litArrayName, literals));
356 return result;
357 }
358
CreateAnnotationElement(const std::string &propName, const ir::Expression *initValue)359 pandasm::AnnotationElement FunctionEmitter::CreateAnnotationElement(const std::string &propName,
360 const ir::Expression *initValue)
361 {
362 if (initValue->IsArrayExpression() || initValue->IsNewExpression()) {
363 std::string baseName {func_->name + "_" + propName};
364 auto litArrays = Emitter::CreateLiteralArray(initValue, baseName);
365 for (auto item : litArrays) {
366 literalArrays_.push_back(item);
367 }
368 return pandasm::AnnotationElement {
369 propName,
370 std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::LITERALARRAY>(
371 std::string_view {litArrays.back().first}))};
372 } else if (initValue->IsNumberLiteral()) {
373 return pandasm::AnnotationElement {
374 propName, std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::F64>(
375 initValue->AsNumberLiteral()->Number()))};
376 } else if (initValue->IsBooleanLiteral()) {
377 return pandasm::AnnotationElement {
378 propName, std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::U1>(
379 initValue->AsBooleanLiteral()->Value()))};
380 } else if (initValue->IsStringLiteral()) {
381 std::string_view stringValue {initValue->AsStringLiteral()->Str().Utf8()};
382 return pandasm::AnnotationElement {
383 propName, std::make_unique<pandasm::ScalarValue>(
384 pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(stringValue))};
385 } else if (initValue->IsUnaryExpression()) {
386 ASSERT(initValue->AsUnaryExpression()->IsNegativeNumber());
387 // In annotations other unary operators (+, !, ~) are evaluated in tsc.
388 // Only unary minus may be present in intermediate .ts
389 double negNumberValue = (-1) * initValue->AsUnaryExpression()->Argument()->AsNumberLiteral()->Number();
390 return pandasm::AnnotationElement {
391 propName, std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::F64>(
392 negNumberValue))};
393 } else {
394 UNREACHABLE();
395 }
396 }
397
CreateExternalAnnotationRecord(const std::string &name)398 static pandasm::Record CreateExternalAnnotationRecord(const std::string &name)
399 {
400 pandasm::Record record(name, pandasm::extensions::Language::ECMASCRIPT);
401 record.metadata->SetAccessFlags(panda::ACC_ANNOTATION);
402 record.metadata->SetAttribute("external");
403 return record;
404 }
405
CreateAnnotation(const ir::Annotation *anno)406 pandasm::AnnotationData FunctionEmitter::CreateAnnotation(const ir::Annotation *anno)
407 {
408 std::string annoName = std::string(anno->Name());
409 if (pg_->Context()->IsMergeAbc()) {
410 std::string prefix = std::string(pg_->Context()->RecordName()) + ".";
411 annoName.insert(0, prefix);
412 }
413 pandasm::AnnotationData annotation(annoName);
414
415 if (anno->IsImported()) {
416 externalAnnotationRecords_.push_back(CreateExternalAnnotationRecord(annoName));
417 }
418
419 if (!anno->Expr()->IsCallExpression()) {
420 [[maybe_unused]] auto checkExpr = anno->Expr()->IsIdentifier() || anno->Expr()->IsMemberExpression();
421 ASSERT(checkExpr == true);
422 return annotation;
423 }
424
425 const ir::CallExpression *callExpr = anno->Expr()->AsCallExpression();
426 if (callExpr->Arguments().size() == 0) {
427 return annotation;
428 }
429
430 // By convention, all properties are initialized in TSC, so that we don't need to process
431 // default arguments in annotation interface declaration
432 for (auto prop : callExpr->Arguments()[0]->AsObjectExpression()->Properties()) {
433 std::string propName {prop->AsProperty()->Key()->AsIdentifier()->Name()};
434 const ir::Expression *initValue = prop->AsProperty()->Value();
435 annotation.AddElement(CreateAnnotationElement(propName, initValue));
436 }
437
438 return annotation;
439 }
440
GenAnnotations()441 void FunctionEmitter::GenAnnotations()
442 {
443 if (!pg_->RootNode()->IsScriptFunction()) {
444 return;
445 }
446
447 auto *scriptFunction = pg_->RootNode()->AsScriptFunction();
448 if (!scriptFunction->Parent() || !scriptFunction->Parent()->Parent() ||
449 !scriptFunction->Parent()->Parent()->IsMethodDefinition()) {
450 return;
451 }
452
453 auto *methodDefinition = scriptFunction->Parent()->Parent()->AsMethodDefinition();
454 std::vector<pandasm::AnnotationData> annotations;
455 for (auto *anno : methodDefinition->Annotations()) {
456 annotations.emplace_back(CreateAnnotation(anno));
457 }
458
459 func_->metadata->AddAnnotations(annotations);
460 }
461
GenFunctionInstructions()462 void FunctionEmitter::GenFunctionInstructions()
463 {
464 func_->ins.reserve(pg_->Insns().size());
465
466 for (const auto *ins : pg_->Insns()) {
467 auto &pandaIns = func_->ins.emplace_back();
468
469 ins->Transform(&pandaIns);
470 GenInstructionDebugInfo(ins, &pandaIns);
471 }
472 }
473
GenFunctionCatchTables()474 void FunctionEmitter::GenFunctionCatchTables()
475 {
476 func_->catch_blocks.reserve(pg_->CatchList().size());
477
478 for (const auto *catchBlock : pg_->CatchList()) {
479 const auto &labelSet = catchBlock->LabelSet();
480
481 auto &pandaCatchBlock = func_->catch_blocks.emplace_back();
482 pandaCatchBlock.try_begin_label = labelSet.TryBegin()->Id();
483 pandaCatchBlock.try_end_label = labelSet.TryEnd()->Id();
484 pandaCatchBlock.catch_begin_label = labelSet.CatchBegin()->Id();
485 pandaCatchBlock.catch_end_label = labelSet.CatchEnd()->Id();
486 }
487 }
488
GenLiteralBuffers()489 void FunctionEmitter::GenLiteralBuffers()
490 {
491 for (const auto *buff : pg_->BuffStorage()) {
492 GenBufferLiterals(buff);
493 }
494 }
495
GenSourceFileDebugInfo()496 void FunctionEmitter::GenSourceFileDebugInfo()
497 {
498 if (pg_->SourceFile().empty()) {
499 func_->source_file = std::string {pg_->Binder()->Program()->SourceFile()};
500 } else {
501 func_->source_file = pg_->SourceFile();
502 }
503
504 if (!pg_->IsDebug()) {
505 return;
506 }
507
508 if (pg_->RootNode()->IsProgram()) {
509 if (pg_->Context()->IsRecordDebugSource()) {
510 func_->source_code = SourceCode().Mutf8();
511 } else {
512 func_->source_code = "not supported";
513 }
514 }
515 }
516
GenScopeVariableInfo(const binder::Scope *scope)517 void FunctionEmitter::GenScopeVariableInfo(const binder::Scope *scope)
518 {
519 const auto *startIns = scope->ScopeStart();
520 const auto *endIns = scope->ScopeEnd();
521
522 uint32_t start = 0;
523 uint32_t count = 0;
524
525 for (const auto *it : pg_->Insns()) {
526 if (startIns == it) {
527 start = count;
528 } else if (endIns == it) {
529 auto varsLength = static_cast<uint32_t>(count - start + 1);
530
531 for (const auto &[name, variable] : scope->Bindings()) {
532 if (!variable->IsLocalVariable() || variable->LexicalBound()) {
533 continue;
534 }
535
536 auto &variableDebug = func_->local_variable_debug.emplace_back();
537 variableDebug.name = name.Mutf8();
538 variableDebug.signature = "any";
539 variableDebug.signature_type = "any";
540 // Register spill causes an offset being applied to all registers in all instructions (refer to
541 // RegAllocator::AdjustInsRegWhenHasSpill for more details). Therefore, we also add this offset
542 // to the variable-to-register mapping before dumping it to the debug information of the abc file
543 // (the following code).
544 // We do not correct the original variable mapping in the scope object since it is not used after
545 // the register spill phase, while we do not know the number of spilled registers before that phase.
546 // If any future modifications require access to the variable mapping after the register spill,
547 // please correct the mapping first and remove the offset increment operation in the following code.
548 variableDebug.reg =
549 static_cast<int32_t>(variable->AsLocalVariable()->Vreg()) + pg_->GetSpillRegsCount();
550 variableDebug.start = start;
551 variableDebug.length = static_cast<uint32_t>(varsLength);
552 }
553
554 break;
555 }
556
557 count++;
558 }
559 }
560
GenVariablesDebugInfo()561 void FunctionEmitter::GenVariablesDebugInfo()
562 {
563 if (!pg_->IsDebug()) {
564 return;
565 }
566
567 for (const auto *scope : pg_->Debuginfo().variableDebugInfo) {
568 GenScopeVariableInfo(scope);
569 }
570 }
571
GenConcurrentFunctionModuleRequests()572 void FunctionEmitter::GenConcurrentFunctionModuleRequests()
573 {
574 if (static_cast<panda::panda_file::FunctionKind>(pg_->GetFunctionKind()) !=
575 panda::panda_file::FunctionKind::CONCURRENT_FUNCTION) {
576 return;
577 }
578
579 std::vector<int> moduleRequests =
580 static_cast<const ir::ScriptFunction *>(pg_->RootNode())->GetConcurrentModuleRequests();
581 func_->concurrent_module_requests.reserve(moduleRequests.size());
582 for (auto it : moduleRequests) {
583 func_->concurrent_module_requests.emplace_back(it);
584 }
585 }
586
587 // Emitter
588
Emitter(CompilerContext *context)589 Emitter::Emitter(CompilerContext *context)
590 {
591 prog_ = new panda::pandasm::Program();
592 prog_->lang = LANG_EXT;
593
594 if (context->IsJsonInputFile()) {
595 GenJsonContentRecord(context);
596 return;
597 }
598
599 if (context->IsMergeAbc()) {
600 auto recordName = context->Binder()->Program()->FormatedRecordName().Mutf8();
601 rec_ = new panda::pandasm::Record(recordName.substr(0, recordName.find_last_of('.')), LANG_EXT);
602 SetPkgNameField(context->PkgName());
603 SetCommonjsField(context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS);
604 } else {
605 rec_ = nullptr;
606 if (context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS) {
607 GenCommonjsRecord();
608 }
609 }
610 if (context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE) {
611 AddHasTopLevelAwaitRecord(context->Binder()->Program()->HasTLA(), context);
612 }
613 AddSharedModuleRecord(context);
614 AddScopeNamesRecord(context);
615 }
616
~Emitter()617 Emitter::~Emitter()
618 {
619 delete prog_;
620 }
621
SetPkgNameField(const std::string &pkgName)622 void Emitter::SetPkgNameField(const std::string &pkgName)
623 {
624 auto pkgNameField = panda::pandasm::Field(LANG_EXT);
625 pkgNameField.name = "pkgName@" + pkgName;
626 pkgNameField.type = panda::pandasm::Type("u8", 0);
627 pkgNameField.metadata->SetValue(
628 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(0)));
629 rec_->field_list.emplace_back(std::move(pkgNameField));
630 }
631
GenRecordNameInfo() const632 void Emitter::GenRecordNameInfo() const
633 {
634 if (rec_) {
635 prog_->record_table.emplace(rec_->name, std::move(*rec_));
636 }
637 }
638
GenJsonContentRecord(const CompilerContext *context)639 void Emitter::GenJsonContentRecord(const CompilerContext *context)
640 {
641 rec_ = new panda::pandasm::Record(std::string(context->RecordName()), panda::panda_file::SourceLang::ECMASCRIPT);
642 auto jsonContentField = panda::pandasm::Field(panda::panda_file::SourceLang::ECMASCRIPT);
643 jsonContentField.name = "jsonFileContent";
644 jsonContentField.type = panda::pandasm::Type("u32", 0);
645 jsonContentField.metadata->SetValue(panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::STRING>(
646 static_cast<std::string_view>(context->SourceFile())));
647 rec_->field_list.emplace_back(std::move(jsonContentField));
648 if (context->PatchFixHelper()) {
649 context->PatchFixHelper()->ProcessJsonContentRecord(rec_->name, context->SourceFile());
650 }
651 }
652
AddFunction(FunctionEmitter *func, CompilerContext *context)653 void Emitter::AddFunction(FunctionEmitter *func, CompilerContext *context)
654 {
655 std::lock_guard<std::mutex> lock(m_);
656
657 for (const auto &str : func->Strings()) {
658 prog_->strings.insert(str.Mutf8());
659 }
660
661 for (auto &[idx, buf] : func->LiteralBuffers()) {
662 auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(buf));
663 auto litId = std::string(context->Binder()->Program()->RecordName()) + "_" + std::to_string(idx);
664 prog_->literalarray_table.emplace(litId, std::move(literalArrayInstance));
665 }
666
667 for (auto &[name, buf] : func->LiteralArrays()) {
668 auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(buf));
669 prog_->literalarray_table.emplace(name, std::move(literalArrayInstance));
670 }
671
672 for (auto &&rec : func->ExternalAnnotationRecords()) {
673 prog_->record_table.emplace(rec.name, std::move(rec));
674 }
675
676 auto *function = func->Function();
677 prog_->function_table.emplace(function->name, std::move(*function));
678 }
679
AddScopeNamesRecord(CompilerContext *context)680 void Emitter::AddScopeNamesRecord(CompilerContext *context)
681 {
682 std::lock_guard<std::mutex> lock(m_);
683 // make literalarray for scope names
684 if (util::Helpers::IsDefaultApiVersion(context->Binder()->Program()->TargetApiVersion(),
685 context->Binder()->Program()->GetTargetApiSubVersion())) {
686 return;
687 }
688 const auto &scopeNamesMap = context->Binder()->GetScopeNames();
689
690 panda::pandasm::LiteralArray array;
691 const int32_t DOUBLE_SIZE = 2;
692 array.literals_.resize(scopeNamesMap.size() * DOUBLE_SIZE);
693 auto strTag = panda_file::LiteralTag::STRING;
694 for (const auto &[scopeName, index] : scopeNamesMap) {
695 panda::pandasm::LiteralArray::Literal tag;
696 tag.tag_ = panda_file::LiteralTag::TAGVALUE;
697 tag.value_ = static_cast<uint8_t>(strTag);
698 array.literals_.at(index * DOUBLE_SIZE) = std::move(tag);
699 panda::pandasm::LiteralArray::Literal val;
700 val.tag_ = strTag;
701 val.value_ = std::string(scopeName);
702 array.literals_.at(index * DOUBLE_SIZE + 1) = std::move(val);
703 }
704 auto literalKey =
705 std::string(context->Binder()->Program()->RecordName()) + "_" + std::to_string(context->NewLiteralIndex());
706 prog_->literalarray_table.emplace(literalKey, std::move(array));
707
708 // ScopeNames is a literalarray in each record if it is in mergeAbc, it is a string array which put scope names.
709 // _ESScopeNamesRecord is a literalarray in the record when it is not in mergeAbc.
710 if (context->IsMergeAbc()) {
711 auto scopeNamesField = panda::pandasm::Field(LANG_EXT);
712 scopeNamesField.name = "scopeNames";
713 scopeNamesField.type = panda::pandasm::Type("u32", 0);
714 scopeNamesField.metadata->SetValue(
715 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
716 static_cast<std::string_view>(literalKey)));
717 rec_->field_list.emplace_back(std::move(scopeNamesField));
718 } else {
719 auto scopeNamesRecord = panda::pandasm::Record("_ESScopeNamesRecord", LANG_EXT);
720 scopeNamesRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
721 auto scopeNamesField = panda::pandasm::Field(LANG_EXT);
722 // If the input arg "source-file" is not specified, context->SourceFile() will be empty,
723 // in this case, use it's absolute path.
724 if (context->SourceFile().empty()) {
725 scopeNamesField.name = context->Binder()->Program()->SourceFile().Mutf8();
726 } else {
727 scopeNamesField.name = context->SourceFile();
728 }
729 scopeNamesField.type = panda::pandasm::Type("u32", 0);
730 scopeNamesField.metadata->SetValue(
731 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
732 static_cast<std::string_view>(literalKey)));
733 scopeNamesRecord.field_list.emplace_back(std::move(scopeNamesField));
734 prog_->record_table.emplace(scopeNamesRecord.name, std::move(scopeNamesRecord));
735 }
736 }
737
CreateStringClass()738 void Emitter::CreateStringClass()
739 {
740 if (prog_->record_table.find(ir::Annotation::stringClassName) == prog_->record_table.end()) {
741 pandasm::Record record(ir::Annotation::stringClassName, pandasm::extensions::Language::ECMASCRIPT);
742 record.metadata->SetAttribute("external");
743 prog_->record_table.emplace(ir::Annotation::stringClassName, std::move(record));
744 }
745 }
746
DeduceArrayEnumType(const ir::Expression *value, uint8_t rank, bool &needToCreateArrayValue)747 panda::pandasm::Type Emitter::DeduceArrayEnumType(const ir::Expression *value, uint8_t rank,
748 bool &needToCreateArrayValue)
749 {
750 // By convention, array of enum must always has initializer
751 ASSERT(value != nullptr);
752 while (value->IsArrayExpression()) {
753 const auto &elements = value->AsArrayExpression()->Elements();
754 value = elements[0];
755 }
756
757 if (value->IsNumberLiteral()) {
758 return panda::pandasm::Type("f64", rank);
759 } else if (value->IsStringLiteral()) {
760 CreateStringClass();
761 return panda::pandasm::Type(ir::Annotation::stringClassName, rank);
762 } else if (value->IsNewExpression()) {
763 const auto &args = value->AsNewExpression()->Arguments();
764 uint8_t value = args[0]->AsNumberLiteral()->Number<uint8_t>();
765 switch (value) {
766 // By convention, this is an array of enums with underlying number type without initializer
767 case ir::Annotation::ENUM_LITERAL_ARRAY_WITHOUT_INITIALIZER_NUMBER_TYPE: {
768 needToCreateArrayValue = false;
769 return panda::pandasm::Type("f64", rank);
770 }
771 case ir::Annotation::ENUM_LITERAL_ARRAY_WITH_EMPTY_INITIALIZER_NUMBER_TYPE: {
772 // By convention, this is an array of enums with underlying number type with empty array initializer
773 needToCreateArrayValue = true;
774 return panda::pandasm::Type("f64", rank);
775 }
776 case ir::Annotation::ENUM_LITERAL_ARRAY_WITHOUT_INITIALIZER_STRING_TYPE: {
777 // By convention, this is an array of enums with underlying string type without initializer
778 needToCreateArrayValue = false;
779 CreateStringClass();
780 return panda::pandasm::Type(ir::Annotation::stringClassName, rank);
781 }
782 case ir::Annotation::ENUM_LITERAL_ARRAY_WITH_EMPTY_INITIALIZER_STRING_TYPE: {
783 // By convention, this is an array of enums with underlying string type with empty array initializer
784 needToCreateArrayValue = true;
785 CreateStringClass();
786 return panda::pandasm::Type(ir::Annotation::stringClassName, rank);
787 }
788 default:
789 UNREACHABLE();
790 }
791 }
792 UNREACHABLE();
793 }
794
CreateLiteralArrayProp(const ir::ClassProperty *prop, const std::string &annoName, panda::pandasm::Field &annoRecordField)795 void Emitter::CreateLiteralArrayProp(const ir::ClassProperty *prop, const std::string &annoName,
796 panda::pandasm::Field &annoRecordField)
797 {
798 uint8_t rank = 1;
799 auto *elemType = prop->TypeAnnotation()->AsTSArrayType()->ElementType();
800 while (elemType->Type() == ir::AstNodeType::TS_ARRAY_TYPE) {
801 ++rank;
802 elemType = elemType->AsTSArrayType()->ElementType();
803 }
804
805 if (elemType->Type() == ir::AstNodeType::TS_NUMBER_KEYWORD) {
806 annoRecordField.type = panda::pandasm::Type("f64", rank);
807 } else if (elemType->Type() == ir::AstNodeType::TS_BOOLEAN_KEYWORD) {
808 annoRecordField.type = panda::pandasm::Type("u1", rank);
809 } else if (elemType->Type() == ir::AstNodeType::TS_STRING_KEYWORD) {
810 CreateStringClass();
811 annoRecordField.type = panda::pandasm::Type(ir::Annotation::stringClassName, rank);
812 } else if (elemType->Type() == ir::AstNodeType::TS_TYPE_REFERENCE) {
813 bool needToCreateArrayValue = true;
814 annoRecordField.type = DeduceArrayEnumType(prop->Value(), rank, needToCreateArrayValue);
815 if (!needToCreateArrayValue) {
816 return;
817 }
818 } else {
819 UNREACHABLE();
820 }
821
822 auto value = prop->Value();
823 if (value != nullptr) {
824 std::string baseName = annoName + "_" + annoRecordField.name;
825 auto litArray = Emitter::CreateLiteralArray(value, baseName);
826 for (auto item : litArray) {
827 prog_->literalarray_table.emplace(item.first, pandasm::LiteralArray(item.second));
828 }
829 annoRecordField.metadata->SetValue(
830 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
831 std::string_view {litArray.back().first}));
832 }
833 }
834
CreateEnumProp(const ir::ClassProperty *prop, const std::string &annoName, panda::pandasm::Field &annoRecordField)835 void Emitter::CreateEnumProp(const ir::ClassProperty *prop, const std::string &annoName,
836 panda::pandasm::Field &annoRecordField)
837 {
838 auto value = prop->Value();
839 if (value == nullptr) {
840 // By convention, if annotation interface prop has no init value,
841 // then underlying type of annotation is string
842 CreateStringClass();
843 annoRecordField.type = panda::pandasm::Type(ir::Annotation::stringClassName, 0);
844 } else if (value->IsTSAsExpression()) {
845 // By convention, if annotation interface prop has init value "new Number(0) as number",
846 // then underlying type of annotation is number
847 annoRecordField.type = panda::pandasm::Type("f64", 0);
848 } else if (value->IsStringLiteral()) {
849 CreateStringClass();
850 annoRecordField.type = panda::pandasm::Type(ir::Annotation::stringClassName, 0);
851 std::string_view stringValue {value->AsStringLiteral()->Str().Utf8()};
852 annoRecordField.metadata->SetValue(
853 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::STRING>(stringValue));
854 } else if (value->IsNumberLiteral()) {
855 annoRecordField.type = panda::pandasm::Type("f64", 0);
856 double doubleValue = value->AsNumberLiteral()->Number();
857 annoRecordField.metadata->SetValue(
858 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::F64>(doubleValue));
859 } else if (value->IsUnaryExpression()) {
860 ASSERT(value->AsUnaryExpression()->IsNegativeNumber());
861 // In annotations other unary operators (+, !, ~) are evaluated in tsc.
862 // Only unary minus may be present in intermediate .ts
863 annoRecordField.type = panda::pandasm::Type("f64", 0);
864 double doubleValue = (-1) * value->AsUnaryExpression()->Argument()->AsNumberLiteral()->Number();
865 annoRecordField.metadata->SetValue(
866 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::F64>(doubleValue));
867 } else {
868 UNREACHABLE();
869 }
870 }
871
CreateAnnotationProp(const ir::ClassProperty *prop, const std::string &annoName)872 panda::pandasm::Field Emitter::CreateAnnotationProp(const ir::ClassProperty *prop, const std::string &annoName)
873 {
874 auto annoRecordField = panda::pandasm::Field(panda::panda_file::SourceLang::ECMASCRIPT);
875 annoRecordField.name = std::string(prop->Key()->AsIdentifier()->Name());
876
877 auto propType = prop->TypeAnnotation()->Type();
878 auto value = prop->Value();
879 if (propType == ir::AstNodeType::TS_NUMBER_KEYWORD) {
880 annoRecordField.type = panda::pandasm::Type("f64", 0);
881 if (value != nullptr) {
882 double doubleValue = 0.0;
883 if (value->IsUnaryExpression()) {
884 ASSERT(value->AsUnaryExpression()->IsNegativeNumber());
885 // In annotations other unary operators (+, !, ~) are evaluated in tsc.
886 // Only unary minus may be present in intermediate .ts
887 value = value->AsUnaryExpression()->Argument();
888 doubleValue = (-1) * value->AsNumberLiteral()->Number();
889 } else {
890 doubleValue = value->AsNumberLiteral()->Number();
891 }
892 annoRecordField.metadata->SetValue(
893 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::F64>(doubleValue));
894 }
895 } else if (propType == ir::AstNodeType::TS_BOOLEAN_KEYWORD) {
896 annoRecordField.type = panda::pandasm::Type("u1", 0);
897 if (value != nullptr) {
898 bool boolValue = value->AsBooleanLiteral()->Value();
899 annoRecordField.metadata->SetValue(
900 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U1>(boolValue));
901 }
902 } else if (propType == ir::AstNodeType::TS_STRING_KEYWORD) {
903 CreateStringClass();
904 annoRecordField.type = panda::pandasm::Type(ir::Annotation::stringClassName, 0);
905 if (value != nullptr) {
906 std::string_view stringValue {value->AsStringLiteral()->Str().Utf8()};
907 annoRecordField.metadata->SetValue(
908 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::STRING>(stringValue));
909 }
910 } else if (propType == ir::AstNodeType::TS_ARRAY_TYPE) {
911 CreateLiteralArrayProp(prop, annoName, annoRecordField);
912 } else if (propType == ir::AstNodeType::TS_TYPE_REFERENCE) {
913 CreateEnumProp(prop, annoName, annoRecordField);
914 } else {
915 UNREACHABLE();
916 }
917
918 return annoRecordField;
919 }
920
AddAnnotationRecord(const std::string &annoName, const ir::ClassDeclaration *classDecl)921 void Emitter::AddAnnotationRecord(const std::string &annoName, const ir::ClassDeclaration *classDecl)
922 {
923 pandasm::Record record(annoName, pandasm::extensions::Language::ECMASCRIPT);
924 record.metadata->SetAccessFlags(panda::ACC_ANNOTATION);
925
926 for (auto bodyItem : classDecl->Definition()->Body()) {
927 record.field_list.emplace_back(CreateAnnotationProp(bodyItem->AsClassProperty(), annoName));
928 }
929
930 prog_->record_table.emplace(annoName, std::move(record));
931 }
932
AddSourceTextModuleRecord(ModuleRecordEmitter *module, CompilerContext *context)933 void Emitter::AddSourceTextModuleRecord(ModuleRecordEmitter *module, CompilerContext *context)
934 {
935 std::lock_guard<std::mutex> lock(m_);
936
937 if (module->NeedEmitPhaseRecord()) {
938 AddModuleRequestPhaseRecord(module, context);
939 }
940
941 auto moduleLiteral = std::string(context->Binder()->Program()->RecordName()) + "_" +
942 std::to_string(module->Index());
943 if (context->IsMergeAbc()) {
944 auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
945 moduleIdxField.name = "moduleRecordIdx";
946 moduleIdxField.type = panda::pandasm::Type("u32", 0);
947 moduleIdxField.metadata->SetValue(
948 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
949 static_cast<std::string_view>(moduleLiteral)));
950 rec_->field_list.emplace_back(std::move(moduleIdxField));
951
952 if (context->PatchFixHelper()) {
953 context->PatchFixHelper()->ProcessModule(rec_->name, module->Buffer());
954 }
955 } else {
956 auto ecmaModuleRecord = panda::pandasm::Record("_ESModuleRecord", LANG_EXT);
957 ecmaModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
958
959 auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
960 moduleIdxField.name = context->Binder()->Program()->ModuleRecordFieldName().empty() ?
961 std::string {context->Binder()->Program()->SourceFile()} :
962 context->Binder()->Program()->ModuleRecordFieldName();
963 moduleIdxField.type = panda::pandasm::Type("u32", 0);
964 moduleIdxField.metadata->SetValue(
965 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
966 static_cast<std::string_view>(moduleLiteral)));
967 ecmaModuleRecord.field_list.emplace_back(std::move(moduleIdxField));
968
969 if (context->PatchFixHelper()) {
970 context->PatchFixHelper()->ProcessModule(ecmaModuleRecord.name, module->Buffer());
971 }
972 prog_->record_table.emplace(ecmaModuleRecord.name, std::move(ecmaModuleRecord));
973 }
974 auto &moduleLiteralsBuffer = module->Buffer();
975 auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(moduleLiteralsBuffer));
976 prog_->literalarray_table.emplace(static_cast<std::string_view>(moduleLiteral), std::move(literalArrayInstance));
977 constant_local_export_slots_ = module->GetConstantLocalExportSlots();
978 }
979
AddModuleRequestPhaseRecord(ModuleRecordEmitter *module, CompilerContext *context)980 void Emitter::AddModuleRequestPhaseRecord(ModuleRecordEmitter *module, CompilerContext *context)
981 {
982 auto phaseLiteral = std::string(context->Binder()->Program()->RecordName()) + "_" +
983 std::to_string(module->PhaseIndex());
984 if (context->IsMergeAbc()) {
985 auto phaseIdxField = panda::pandasm::Field(LANG_EXT);
986 phaseIdxField.name = "moduleRequestPhaseIdx";
987 phaseIdxField.type = panda::pandasm::Type("u32", 0);
988 phaseIdxField.metadata->SetValue(
989 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
990 static_cast<std::string_view>(phaseLiteral)));
991 rec_->field_list.emplace_back(std::move(phaseIdxField));
992 } else {
993 auto moduleRequestPhaseRecord = panda::pandasm::Record("_ModuleRequestPhaseRecord", LANG_EXT);
994 moduleRequestPhaseRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
995
996 auto phaseIdxField = panda::pandasm::Field(LANG_EXT);
997 phaseIdxField.name = "moduleRequestPhaseIdx";
998 phaseIdxField.type = panda::pandasm::Type("u32", 0);
999 phaseIdxField.metadata->SetValue(
1000 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
1001 static_cast<std::string_view>(phaseLiteral)));
1002 moduleRequestPhaseRecord.field_list.emplace_back(std::move(phaseIdxField));
1003
1004 prog_->record_table.emplace(moduleRequestPhaseRecord.name, std::move(moduleRequestPhaseRecord));
1005 }
1006 auto &moduleRequestPhaseLiteralsBuffer = module->PhaseBuffer();
1007 auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(moduleRequestPhaseLiteralsBuffer));
1008 prog_->literalarray_table.emplace(static_cast<std::string_view>(phaseLiteral), std::move(literalArrayInstance));
1009 }
1010
AddHasTopLevelAwaitRecord(bool hasTLA, const CompilerContext *context)1011 void Emitter::AddHasTopLevelAwaitRecord(bool hasTLA, const CompilerContext *context)
1012 {
1013 if (context->IsMergeAbc()) {
1014 auto hasTLAField = panda::pandasm::Field(LANG_EXT);
1015 hasTLAField.name = "hasTopLevelAwait";
1016 hasTLAField.type = panda::pandasm::Type("u8", 0);
1017 hasTLAField.metadata->SetValue(
1018 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(hasTLA)));
1019 rec_->field_list.emplace_back(std::move(hasTLAField));
1020 } else if (hasTLA) {
1021 auto hasTLARecord = panda::pandasm::Record("_HasTopLevelAwait", LANG_EXT);
1022 hasTLARecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
1023 auto hasTLAField = panda::pandasm::Field(LANG_EXT);
1024 hasTLAField.name = "hasTopLevelAwait";
1025 hasTLAField.type = panda::pandasm::Type("u8", 0);
1026 hasTLAField.metadata->SetValue(
1027 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(true)));
1028 hasTLARecord.field_list.emplace_back(std::move(hasTLAField));
1029
1030 prog_->record_table.emplace(hasTLARecord.name, std::move(hasTLARecord));
1031 }
1032 }
1033
AddSharedModuleRecord(const CompilerContext *context)1034 void Emitter::AddSharedModuleRecord(const CompilerContext *context)
1035 {
1036 bool isShared = context->Binder()->Program()->IsShared();
1037
1038 auto sharedModuleField = panda::pandasm::Field(LANG_EXT);
1039 sharedModuleField.name = "isSharedModule";
1040 sharedModuleField.type = panda::pandasm::Type("u8", 0);
1041 sharedModuleField.metadata->SetValue(
1042 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(isShared)));
1043
1044 if (context->IsMergeAbc()) {
1045 rec_->field_list.emplace_back(std::move(sharedModuleField));
1046 } else if (isShared) {
1047 auto sharedModuleRecord = panda::pandasm::Record("_SharedModuleRecord", LANG_EXT);
1048 sharedModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
1049 sharedModuleRecord.field_list.emplace_back(std::move(sharedModuleField));
1050 prog_->record_table.emplace(sharedModuleRecord.name, std::move(sharedModuleRecord));
1051 }
1052 }
1053
1054 // static
GenBufferLiterals(ArenaVector<std::pair<int32_t, std::vector<Literal>>> &literalBuffers, const LiteralBuffer *buff)1055 void Emitter::GenBufferLiterals(ArenaVector<std::pair<int32_t, std::vector<Literal>>> &literalBuffers,
1056 const LiteralBuffer *buff)
1057 {
1058 auto &[idx, array] = literalBuffers.emplace_back();
1059 idx = buff->Index();
1060 constexpr size_t ARRAY_EXPANSION = 2;
1061 array.reserve(buff->Literals().size() * ARRAY_EXPANSION);
1062
1063 for (const auto *literal : buff->Literals()) {
1064 panda::pandasm::LiteralArray::Literal valueLit;
1065 panda::pandasm::LiteralArray::Literal tagLit;
1066
1067 ir::LiteralTag tag = literal->Tag();
1068
1069 switch (tag) {
1070 case ir::LiteralTag::BOOLEAN: {
1071 valueLit.tag_ = panda::panda_file::LiteralTag::BOOL;
1072 valueLit.value_ = literal->GetBoolean();
1073 break;
1074 }
1075 case ir::LiteralTag::INTEGER: {
1076 valueLit.tag_ = panda::panda_file::LiteralTag::INTEGER;
1077 valueLit.value_ = literal->GetInt();
1078 break;
1079 }
1080 case ir::LiteralTag::DOUBLE: {
1081 valueLit.tag_ = panda::panda_file::LiteralTag::DOUBLE;
1082 valueLit.value_ = literal->GetDouble();
1083 break;
1084 }
1085 case ir::LiteralTag::STRING: {
1086 valueLit.tag_ = panda::panda_file::LiteralTag::STRING;
1087 valueLit.value_ = literal->GetString().Mutf8();
1088 break;
1089 }
1090 case ir::LiteralTag::ACCESSOR: {
1091 valueLit.tag_ = panda::panda_file::LiteralTag::ACCESSOR;
1092 valueLit.value_ = static_cast<uint8_t>(0);
1093 break;
1094 }
1095 case ir::LiteralTag::METHOD: {
1096 valueLit.tag_ = panda::panda_file::LiteralTag::METHOD;
1097 valueLit.value_ = literal->GetMethod().Mutf8();
1098 break;
1099 }
1100 case ir::LiteralTag::METHODAFFILIATE: {
1101 valueLit.tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE;
1102 valueLit.value_ = literal->GetMethodAffiliate();
1103 break;
1104 }
1105 case ir::LiteralTag::GENERATOR_METHOD: {
1106 valueLit.tag_ = panda::panda_file::LiteralTag::GENERATORMETHOD;
1107 valueLit.value_ = literal->GetMethod().Mutf8();
1108 break;
1109 }
1110 case ir::LiteralTag::LITERALBUFFERINDEX: {
1111 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALBUFFERINDEX;
1112 valueLit.value_ = literal->GetInt();
1113 break;
1114 }
1115 case ir::LiteralTag::LITERALARRAY: {
1116 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALARRAY;
1117 valueLit.value_ = literal->GetString().Mutf8();
1118 break;
1119 }
1120 case ir::LiteralTag::BUILTINTYPEINDEX: {
1121 valueLit.tag_ = panda::panda_file::LiteralTag::BUILTINTYPEINDEX;
1122 valueLit.value_ = static_cast<uint8_t>(literal->GetInt());
1123 break;
1124 }
1125 case ir::LiteralTag::GETTER: {
1126 valueLit.tag_ = panda::panda_file::LiteralTag::GETTER;
1127 valueLit.value_ = literal->GetMethod().Mutf8();
1128 break;
1129 }
1130 case ir::LiteralTag::SETTER: {
1131 valueLit.tag_ = panda::panda_file::LiteralTag::SETTER;
1132 valueLit.value_ = literal->GetMethod().Mutf8();
1133 break;
1134 }
1135 case ir::LiteralTag::ASYNC_GENERATOR_METHOD: {
1136 valueLit.tag_ = panda::panda_file::LiteralTag::ASYNCGENERATORMETHOD;
1137 valueLit.value_ = literal->GetMethod().Mutf8();
1138 break;
1139 }
1140 case ir::LiteralTag::NULL_VALUE: {
1141 valueLit.tag_ = panda::panda_file::LiteralTag::NULLVALUE;
1142 valueLit.value_ = static_cast<uint8_t>(0);
1143 break;
1144 }
1145 default:
1146 break;
1147 }
1148
1149 tagLit.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
1150 tagLit.value_ = static_cast<uint8_t>(valueLit.tag_);
1151
1152 array.emplace_back(tagLit);
1153 array.emplace_back(valueLit);
1154 }
1155 }
1156
DumpAsm(const panda::pandasm::Program *prog)1157 void Emitter::DumpAsm(const panda::pandasm::Program *prog)
1158 {
1159 auto &ss = std::cout;
1160
1161 ss << ".language ECMAScript" << std::endl << std::endl;
1162
1163 for (auto &[name, func] : prog->function_table) {
1164 ss << "slotNum = 0x" << std::hex << func.GetSlotsNum() << std::dec << std::endl;
1165 ss << ".function any " << name << '(';
1166
1167 for (uint32_t i = 0; i < func.GetParamsNum(); i++) {
1168 ss << "any a" << std::to_string(i);
1169
1170 if (i != func.GetParamsNum() - 1) {
1171 ss << ", ";
1172 }
1173 }
1174
1175 ss << ") {" << std::endl;
1176
1177 for (const auto &ins : func.ins) {
1178 ss << (ins.set_label ? "" : "\t") << ins.ToString("", true, func.GetTotalRegs()) << std::endl;
1179 }
1180
1181 ss << "}" << std::endl << std::endl;
1182
1183 for (const auto &ct : func.catch_blocks) {
1184 ss << ".catchall " << ct.try_begin_label << ", " << ct.try_end_label << ", " << ct.catch_begin_label
1185 << std::endl
1186 << std::endl;
1187 }
1188 }
1189
1190 ss << std::endl;
1191 }
1192
Finalize(bool dumpDebugInfo, util::PatchFix *patchFixHelper)1193 panda::pandasm::Program *Emitter::Finalize(bool dumpDebugInfo, util::PatchFix *patchFixHelper)
1194 {
1195 if (dumpDebugInfo) {
1196 debuginfo::DebugInfoDumper dumper(prog_);
1197 dumper.Dump();
1198 }
1199
1200 if (rec_) {
1201 delete rec_;
1202 rec_ = nullptr;
1203 }
1204
1205 if (patchFixHelper) {
1206 patchFixHelper->Finalize(&prog_);
1207 }
1208
1209 auto *prog = prog_;
1210 prog_ = nullptr;
1211 return prog;
1212 }
1213
GetProgram() const1214 panda::pandasm::Program *Emitter::GetProgram() const
1215 {
1216 return prog_;
1217 }
1218
1219 } // namespace panda::es2panda::compiler
1220