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