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 39namespace ark::es2panda::compiler { 40using LiteralPair = std::pair<pandasm::LiteralArray::Literal, pandasm::LiteralArray::Literal>; 41 42static 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 82static 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 130void FunctionEmitter::Generate() 131{ 132 auto *func = GenFunctionSignature(); 133 GenFunctionInstructions(func); 134 GenVariablesDebugInfo(func); 135 GenSourceFileDebugInfo(func); 136 GenFunctionCatchTables(func); 137 GenFunctionAnnotations(func); 138} 139 140util::StringView FunctionEmitter::SourceCode() const 141{ 142 return cg_->VarBinder()->Program()->SourceCode(); 143} 144 145static 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 172static 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 189static 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 199void 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 227void 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 241void 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 262void 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 278void 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 291static 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 315void 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 357void 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 396void 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 409Emitter::Emitter(const public_lib::Context *context) : context_(context) 410{ 411 prog_ = new pandasm::Program(); 412} 413 414Emitter::~Emitter() 415{ 416 delete prog_; 417} 418 419static 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 446void 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 465static 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 474void 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 512void 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 526pandasm::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