1 /**
2 * Copyright (c) 2021 - 2024 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 "ir/irnode.h"
19 #include "util/helpers.h"
20 #include "varbinder/scope.h"
21 #include "varbinder/variable.h"
22 #include "compiler/base/literals.h"
23 #include "compiler/core/codeGen.h"
24 #include "compiler/core/regSpiller.h"
25 #include "compiler/debugger/debuginfoDumper.h"
26 #include "compiler/base/catchTable.h"
27 #include "es2panda.h"
28 #include "parser/program/program.h"
29 #include "checker/types/type.h"
30 #include "generated/isa.h"
31 #include "macros.h"
32 #include "public/public.h"
33
34 #include <string>
35 #include <string_view>
36 #include <tuple>
37 #include <utility>
38
39 namespace ark::es2panda::compiler {
40 using LiteralPair = std::pair<pandasm::LiteralArray::Literal, pandasm::LiteralArray::Literal>;
41
TransformMethodLiterals(const compiler::Literal * literal)42 static LiteralPair TransformMethodLiterals(const compiler::Literal *literal)
43 {
44 pandasm::LiteralArray::Literal valueLit;
45 pandasm::LiteralArray::Literal tagLit;
46
47 compiler::LiteralTag tag = literal->Tag();
48
49 switch (tag) {
50 case compiler::LiteralTag::METHOD: {
51 valueLit.tag = panda_file::LiteralTag::METHOD;
52 valueLit.value = literal->GetMethod();
53 break;
54 }
55 case compiler::LiteralTag::ASYNC_METHOD: {
56 valueLit.tag = panda_file::LiteralTag::ASYNCMETHOD;
57 valueLit.value = literal->GetMethod();
58 break;
59 }
60 case compiler::LiteralTag::GENERATOR_METHOD: {
61 valueLit.tag = panda_file::LiteralTag::GENERATORMETHOD;
62 valueLit.value = literal->GetMethod();
63 break;
64 }
65 case compiler::LiteralTag::ASYNC_GENERATOR_METHOD: {
66 valueLit.tag = panda_file::LiteralTag::ASYNCGENERATORMETHOD;
67 valueLit.value = literal->GetMethod();
68 break;
69 }
70 default: {
71 UNREACHABLE();
72 break;
73 }
74 }
75
76 tagLit.tag = panda_file::LiteralTag::TAGVALUE;
77 tagLit.value = static_cast<uint8_t>(valueLit.tag);
78
79 return {tagLit, valueLit};
80 }
81
TransformLiteral(const compiler::Literal * literal)82 static LiteralPair TransformLiteral(const compiler::Literal *literal)
83 {
84 pandasm::LiteralArray::Literal valueLit;
85 pandasm::LiteralArray::Literal tagLit;
86
87 compiler::LiteralTag tag = literal->Tag();
88
89 switch (tag) {
90 case compiler::LiteralTag::BOOLEAN: {
91 valueLit.tag = panda_file::LiteralTag::BOOL;
92 valueLit.value = literal->GetBoolean();
93 break;
94 }
95 case compiler::LiteralTag::INTEGER: {
96 valueLit.tag = panda_file::LiteralTag::INTEGER;
97 valueLit.value = literal->GetInteger();
98 break;
99 }
100 case compiler::LiteralTag::DOUBLE: {
101 valueLit.tag = panda_file::LiteralTag::DOUBLE;
102 valueLit.value = literal->GetDouble();
103 break;
104 }
105 case compiler::LiteralTag::STRING: {
106 valueLit.tag = panda_file::LiteralTag::STRING;
107 valueLit.value = literal->GetString();
108 break;
109 }
110 case compiler::LiteralTag::ACCESSOR: {
111 valueLit.tag = panda_file::LiteralTag::ACCESSOR;
112 valueLit.value = static_cast<uint8_t>(0);
113 break;
114 }
115 case compiler::LiteralTag::NULL_VALUE: {
116 valueLit.tag = panda_file::LiteralTag::NULLVALUE;
117 valueLit.value = static_cast<uint8_t>(0);
118 break;
119 }
120 default:
121 return TransformMethodLiterals(literal);
122 }
123
124 tagLit.tag = panda_file::LiteralTag::TAGVALUE;
125 tagLit.value = static_cast<uint8_t>(valueLit.tag);
126
127 return {tagLit, valueLit};
128 }
129
Generate()130 void FunctionEmitter::Generate()
131 {
132 auto *func = GenFunctionSignature();
133 GenFunctionInstructions(func);
134 GenVariablesDebugInfo(func);
135 GenSourceFileDebugInfo(func);
136 GenFunctionCatchTables(func);
137 GenFunctionAnnotations(func);
138 }
139
SourceCode() const140 util::StringView FunctionEmitter::SourceCode() const
141 {
142 return cg_->VarBinder()->Program()->SourceCode();
143 }
144
MatchFormat(const IRNode * node,const Formats & formats)145 static Format MatchFormat(const IRNode *node, const Formats &formats)
146 {
147 std::array<const VReg *, IRNode::MAX_REG_OPERAND> regs {};
148 auto regCnt = node->Registers(®s);
149 auto registers = Span<const VReg *>(regs.data(), regs.data() + regCnt);
150
151 const auto *iter = formats.begin();
152
153 for (; iter != formats.end(); iter++) { // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
154 auto format = *iter;
155 size_t limit = 0;
156 for (const auto &formatItem : format.GetFormatItem()) {
157 if (formatItem.IsVReg()) {
158 limit = 1U << formatItem.BitWidth();
159 break;
160 }
161 }
162
163 if (std::all_of(registers.begin(), registers.end(), [limit](const VReg *reg) { return reg->IsValid(limit); })) {
164 return format;
165 }
166 }
167
168 UNREACHABLE();
169 return *iter;
170 }
171
GetIRNodeWholeLength(const IRNode * node)172 static size_t GetIRNodeWholeLength(const IRNode *node)
173 {
174 Formats formats = node->GetFormats();
175 if (formats.empty()) {
176 return 0;
177 }
178
179 size_t len = 1;
180 const auto format = MatchFormat(node, formats);
181
182 for (auto fi : format.GetFormatItem()) {
183 len += fi.BitWidth() / 8U;
184 }
185
186 return len;
187 }
188
WholeLine(const util::StringView & source,lexer::SourceRange range)189 static std::string WholeLine(const util::StringView &source, lexer::SourceRange range)
190 {
191 if (source.Empty()) {
192 return {};
193 }
194 ASSERT(range.end.index <= source.Length());
195 ASSERT(range.end.index >= range.start.index);
196 return source.Substr(range.start.index, range.end.index).EscapeSymbol<util::StringView::Mutf8Encode>();
197 }
198
GenInstructionDebugInfo(const IRNode * ins,pandasm::Ins * pandaIns)199 void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, pandasm::Ins *pandaIns)
200 {
201 const ir::AstNode *astNode = ins->Node();
202
203 ASSERT(astNode != nullptr);
204
205 if (astNode == FIRST_NODE_OF_FUNCTION) {
206 astNode = cg_->Debuginfo().FirstStatement();
207 if (astNode == nullptr) {
208 return;
209 }
210 }
211
212 auto nodeRange = astNode->Range();
213 pandaIns->insDebug.lineNumber = nodeRange.start.line + 1;
214
215 if (cg_->IsDebug()) {
216 size_t insLen = GetIRNodeWholeLength(ins);
217 if (insLen != 0) {
218 pandaIns->insDebug.boundLeft = offset_;
219 pandaIns->insDebug.boundRight = offset_ + insLen;
220 }
221
222 offset_ += insLen;
223 pandaIns->insDebug.wholeLine = WholeLine(SourceCode(), nodeRange);
224 }
225 }
226
GenFunctionInstructions(pandasm::Function * func)227 void FunctionEmitter::GenFunctionInstructions(pandasm::Function *func)
228 {
229 func->ins.reserve(cg_->Insns().size());
230
231 uint32_t totalRegs = cg_->TotalRegsNum();
232
233 for (const auto *ins : cg_->Insns()) {
234 auto &pandaIns = func->ins.emplace_back();
235
236 ins->Transform(&pandaIns, programElement_, totalRegs);
237 GenInstructionDebugInfo(ins, &pandaIns);
238 }
239 }
240
GenFunctionAnnotations(pandasm::Function * func)241 void FunctionEmitter::GenFunctionAnnotations(pandasm::Function *func)
242 {
243 pandasm::AnnotationData funcAnnotationData("_ESAnnotation");
244 pandasm::AnnotationElement icSizeAnnotationElement(
245 "icSize",
246 std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::U32>(cg_->IcSize())));
247 funcAnnotationData.AddElement(std::move(icSizeAnnotationElement));
248
249 pandasm::AnnotationElement parameterLengthAnnotationElement(
250 "parameterLength", std::make_unique<pandasm::ScalarValue>(
251 pandasm::ScalarValue::Create<pandasm::Value::Type::U32>(cg_->FormalParametersCount())));
252 funcAnnotationData.AddElement(std::move(parameterLengthAnnotationElement));
253
254 pandasm::AnnotationElement funcNameAnnotationElement(
255 "funcName", std::make_unique<pandasm::ScalarValue>(
256 pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(cg_->FunctionName().Mutf8())));
257 funcAnnotationData.AddElement(std::move(funcNameAnnotationElement));
258
259 func->metadata->AddAnnotations({funcAnnotationData});
260 }
261
GenFunctionCatchTables(pandasm::Function * func)262 void FunctionEmitter::GenFunctionCatchTables(pandasm::Function *func)
263 {
264 func->catchBlocks.reserve(cg_->CatchList().size());
265
266 for (const auto *catchBlock : cg_->CatchList()) {
267 const auto &labelSet = catchBlock->LabelSet();
268
269 auto &pandaCatchBlock = func->catchBlocks.emplace_back();
270 pandaCatchBlock.exceptionRecord = catchBlock->Exception();
271 pandaCatchBlock.tryBeginLabel = labelSet.TryBegin()->Id();
272 pandaCatchBlock.tryEndLabel = labelSet.TryEnd()->Id();
273 pandaCatchBlock.catchBeginLabel = labelSet.CatchBegin()->Id();
274 pandaCatchBlock.catchEndLabel = labelSet.CatchBegin()->Id();
275 }
276 }
277
GenSourceFileDebugInfo(pandasm::Function * func)278 void FunctionEmitter::GenSourceFileDebugInfo(pandasm::Function *func)
279 {
280 func->sourceFile = std::string {cg_->VarBinder()->Program()->SourceFile().GetAbsolutePath()};
281
282 if (!cg_->IsDebug()) {
283 return;
284 }
285
286 if (cg_->RootNode()->IsProgram()) {
287 func->sourceCode = SourceCode().EscapeSymbol<util::StringView::Mutf8Encode>();
288 }
289 }
290
GenLocalVariableInfo(pandasm::debuginfo::LocalVariable & variableDebug,varbinder::Variable * var,std::tuple<uint32_t,uint32_t,uint32_t> info,const ScriptExtension extension)291 static void GenLocalVariableInfo(pandasm::debuginfo::LocalVariable &variableDebug, varbinder::Variable *var,
292 std::tuple<uint32_t, uint32_t, uint32_t> info, const ScriptExtension extension)
293 {
294 const auto [start, varsLength, totalRegsNum] = info;
295
296 variableDebug.name = var->Name().Mutf8();
297
298 if (extension == ScriptExtension::JS) {
299 variableDebug.signature = "any";
300 variableDebug.signatureType = "any";
301 } else {
302 ASSERT(var->AsLocalVariable()->TsType() != nullptr);
303 std::stringstream ss;
304 var->AsLocalVariable()->TsType()->ToDebugInfoType(ss);
305 variableDebug.signature = ss.str();
306 variableDebug.signatureType = ss.str(); // NOTE: Handle typeParams, either class or interface
307 }
308
309 variableDebug.reg =
310 static_cast<int32_t>(IRNode::MapRegister(var->AsLocalVariable()->Vreg().GetIndex(), totalRegsNum));
311 variableDebug.start = start;
312 variableDebug.length = static_cast<uint32_t>(varsLength);
313 }
314
GenScopeVariableInfoEnd(pandasm::Function * func,const varbinder::Scope * scope,uint32_t count,uint32_t scopeStart,const VariablesStartsMap & starts) const315 void FunctionEmitter::GenScopeVariableInfoEnd(pandasm::Function *func, const varbinder::Scope *scope, uint32_t count,
316 uint32_t scopeStart, const VariablesStartsMap &starts) const
317 {
318 const auto extension = cg_->VarBinder()->Program()->Extension();
319 auto varsLength = static_cast<uint32_t>(count - scopeStart + 1);
320
321 if (scope->IsFunctionScope()) {
322 for (auto *param : scope->AsFunctionScope()->ParamScope()->Params()) {
323 auto &variableDebug = func->localVariableDebug.emplace_back();
324 GenLocalVariableInfo(variableDebug, param, std::make_tuple(scopeStart, varsLength, cg_->TotalRegsNum()),
325 extension);
326 }
327 }
328 const auto &unsortedBindings = scope->Bindings();
329 std::map<util::StringView, es2panda::varbinder::Variable *> bindings(unsortedBindings.begin(),
330 unsortedBindings.end());
331 for (const auto &[_, variable] : bindings) {
332 (void)_;
333 const auto *decl = variable->Declaration();
334 // NOTE(dslynko, #19203): do not generate debug-info for labels and local classes and interfaces
335 if (!variable->IsLocalVariable() || variable->LexicalBound() || decl->IsTypeAliasDecl() ||
336 decl->IsLabelDecl() || decl->IsClassDecl() || decl->IsInterfaceDecl()) {
337 continue;
338 }
339 if (decl->IsParameterDecl() && !scope->IsCatchParamScope()) {
340 continue;
341 }
342
343 uint32_t localStart = scopeStart;
344 uint32_t localLength = varsLength;
345 auto iter = starts.find(variable);
346 if (iter != starts.end()) {
347 localStart = iter->second;
348 localLength = static_cast<uint32_t>(count - localStart + 1);
349 }
350
351 auto &variableDebug = func->localVariableDebug.emplace_back();
352 GenLocalVariableInfo(variableDebug, variable, std::make_tuple(localStart, localLength, cg_->TotalRegsNum()),
353 extension);
354 }
355 }
356
GenScopeVariableInfo(pandasm::Function * func,const varbinder::Scope * scope) const357 void FunctionEmitter::GenScopeVariableInfo(pandasm::Function *func, const varbinder::Scope *scope) const
358 {
359 const auto &instructions = cg_->Insns();
360 auto lastIter = instructions.end();
361 auto iter = std::find(instructions.begin(), lastIter, scope->ScopeStart());
362 if (iter == lastIter || *iter == scope->ScopeEnd()) {
363 return;
364 }
365 uint32_t count = iter - instructions.begin();
366 uint32_t start = count;
367
368 auto checkNodeIsValid = [](const ir::AstNode *node) { return node != nullptr && node != FIRST_NODE_OF_FUNCTION; };
369 // NOTE(dslynko, #19090): need to track start location for each local variable
370 std::unordered_map<const varbinder::Variable *, uint32_t> varsStarts;
371 for (const auto *scopeEnd = scope->ScopeEnd(); iter != lastIter && *iter != scopeEnd; ++iter, ++count) {
372 const auto *node = (*iter)->Node();
373 if (!checkNodeIsValid(node)) {
374 continue;
375 }
376 auto *parent = node->Parent();
377 if (!checkNodeIsValid(parent)) {
378 continue;
379 }
380
381 const varbinder::Variable *var = nullptr;
382 if (parent->IsVariableDeclarator()) {
383 var = parent->AsVariableDeclarator()->Id()->Variable();
384 } else if (parent->IsCatchClause()) {
385 var = node->Variable();
386 }
387 if (var != nullptr && varsStarts.count(var) == 0) {
388 varsStarts.emplace(var, count);
389 }
390 }
391 ASSERT(iter != lastIter);
392
393 GenScopeVariableInfoEnd(func, scope, count, start, varsStarts);
394 }
395
GenVariablesDebugInfo(pandasm::Function * func)396 void FunctionEmitter::GenVariablesDebugInfo(pandasm::Function *func)
397 {
398 if (!cg_->IsDebug()) {
399 return;
400 }
401
402 for (const auto *scope : cg_->Debuginfo().VariableDebugInfo()) {
403 GenScopeVariableInfo(func, scope);
404 }
405 }
406
407 // Emitter
408
Emitter(const public_lib::Context * context)409 Emitter::Emitter(const public_lib::Context *context) : context_(context)
410 {
411 prog_ = new pandasm::Program();
412 }
413
~Emitter()414 Emitter::~Emitter()
415 {
416 delete prog_;
417 }
418
UpdateLiteralBufferId(ark::pandasm::Ins * ins,uint32_t offset)419 static void UpdateLiteralBufferId([[maybe_unused]] ark::pandasm::Ins *ins, [[maybe_unused]] uint32_t offset)
420 {
421 #ifdef PANDA_WITH_ECMASCRIPT
422 switch (ins->opcode) {
423 case pandasm::Opcode::ECMA_DEFINECLASSWITHBUFFER: {
424 ins->imms.back() = std::get<int64_t>(ins->imms.back()) + offset;
425 break;
426 }
427 case pandasm::Opcode::ECMA_CREATEARRAYWITHBUFFER:
428 case pandasm::Opcode::ECMA_CREATEOBJECTWITHBUFFER:
429 case pandasm::Opcode::ECMA_CREATEOBJECTHAVINGMETHOD:
430 case pandasm::Opcode::ECMA_DEFINECLASSPRIVATEFIELDS: {
431 uint32_t storedOffset = std::stoi(ins->ids.back());
432 storedOffset += offset;
433 ins->ids.back() = std::to_string(storedOffset);
434 break;
435 }
436 default: {
437 UNREACHABLE();
438 break;
439 }
440 }
441 #else
442 UNREACHABLE();
443 #endif
444 }
445
AddProgramElement(ProgramElement * programElement)446 void Emitter::AddProgramElement(ProgramElement *programElement)
447 {
448 prog_->strings.insert(programElement->Strings().begin(), programElement->Strings().end());
449
450 uint32_t newLiteralBufferIndex = literalBufferIndex_;
451 for (const auto &buff : programElement->BuffStorage()) {
452 AddLiteralBuffer(buff, newLiteralBufferIndex++);
453 }
454
455 for (auto *ins : programElement->LiteralBufferIns()) {
456 UpdateLiteralBufferId(ins, literalBufferIndex_);
457 }
458
459 literalBufferIndex_ = newLiteralBufferIndex;
460
461 auto *function = programElement->Function();
462 prog_->functionTable.emplace(function->name, std::move(*function));
463 }
464
CanonicalizeName(std::string name)465 static std::string CanonicalizeName(std::string name)
466 {
467 std::replace_if(
468 name.begin(), name.end(), [](char c) { return (c == '<' || c == '>' || c == '.' || c == ':' || c == ';'); },
469 '-');
470 name.append(std::to_string(0));
471 return name;
472 }
473
DumpAsm(const pandasm::Program * prog)474 void Emitter::DumpAsm(const pandasm::Program *prog)
475 {
476 auto &ss = std::cout;
477
478 ss << ".language ECMAScript" << std::endl << std::endl;
479
480 for (auto &[name, func] : prog->functionTable) {
481 ss << ".function any " << CanonicalizeName(name) << '(';
482
483 for (uint32_t i = 0; i < func.GetParamsNum(); i++) {
484 ss << "any a" << std::to_string(i);
485
486 if (i != func.GetParamsNum() - 1) {
487 ss << ", ";
488 }
489 }
490
491 ss << ") {" << std::endl;
492
493 for (const auto &ins : func.ins) {
494 ss << (ins.setLabel ? "" : "\t") << ins.ToString("", true, func.GetTotalRegs()) << std::endl;
495 }
496
497 ss << "}" << std::endl << std::endl;
498
499 for (const auto &ct : func.catchBlocks) {
500 if (ct.exceptionRecord.empty()) {
501 ss << ".catchall ";
502 } else {
503 ss << ".catch " << ct.exceptionRecord << ", ";
504 }
505 ss << ct.tryBeginLabel << ", " << ct.tryEndLabel << ", " << ct.catchBeginLabel << std::endl << std::endl;
506 }
507 }
508
509 ss << std::endl;
510 }
511
AddLiteralBuffer(const LiteralBuffer & literals,uint32_t index)512 void Emitter::AddLiteralBuffer(const LiteralBuffer &literals, uint32_t index)
513 {
514 std::vector<pandasm::LiteralArray::Literal> literalArray;
515
516 for (const auto &literal : literals) {
517 auto [tagLit, valueLit] = TransformLiteral(&literal);
518 literalArray.emplace_back(tagLit);
519 literalArray.emplace_back(valueLit);
520 }
521
522 auto literalArrayInstance = pandasm::LiteralArray(std::move(literalArray));
523 prog_->literalarrayTable.emplace(std::to_string(index), std::move(literalArrayInstance));
524 }
525
Finalize(bool dumpDebugInfo,std::string_view globalClass)526 pandasm::Program *Emitter::Finalize(bool dumpDebugInfo, std::string_view globalClass)
527 {
528 if (dumpDebugInfo) {
529 debuginfo::DebugInfoDumper dumper(prog_);
530 dumper.Dump();
531 }
532
533 if (context_->parserProgram->VarBinder()->IsGenStdLib()) {
534 auto it = prog_->recordTable.find(std::string(globalClass));
535 if (it != prog_->recordTable.end()) {
536 prog_->recordTable.erase(it);
537 }
538 }
539 auto *prog = prog_;
540 prog_ = nullptr;
541 return prog;
542 }
543 } // namespace ark::es2panda::compiler
544