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