• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "emitter.h"
17 
18 #include <binder/binder.h>
19 #include <binder/scope.h>
20 #include <binder/variable.h>
21 #include <compiler/base/literals.h>
22 #include <compiler/core/compilerContext.h>
23 #include <compiler/core/emitter/typeExtractorEmitter.h>
24 #include <compiler/core/pandagen.h>
25 #include <compiler/debugger/debuginfoDumper.h>
26 #include <compiler/base/catchTable.h>
27 #include <es2panda.h>
28 #include <gen/isa.h>
29 #include <ir/expressions/literal.h>
30 #include <ir/statements/blockStatement.h>
31 #include <macros.h>
32 #include <parser/program/program.h>
33 #include <util/helpers.h>
34 
35 #include <string>
36 #include <string_view>
37 #include <tuple>
38 #include <utility>
39 
40 namespace panda::es2panda::compiler {
41 constexpr const auto LANG_EXT = panda::pandasm::extensions::Language::ECMASCRIPT;
42 
FunctionEmitter(ArenaAllocator * allocator,const PandaGen * pg)43 FunctionEmitter::FunctionEmitter(ArenaAllocator *allocator, const PandaGen *pg)
44     : pg_(pg), literalBuffers_(allocator->Adapter())
45 {
46     func_ = allocator->New<panda::pandasm::Function>(pg->InternalName().Mutf8(), LANG_EXT);
47 
48     size_t paramCount = pg->InternalParamCount();
49     func_->params.reserve(paramCount);
50 
51     for (uint32_t i = 0; i < paramCount; ++i) {
52         func_->params.emplace_back(panda::pandasm::Type("any", 0), LANG_EXT);
53     }
54 
55     func_->regs_num = pg->TotalRegsNum();
56     func_->return_type = panda::pandasm::Type("any", 0);
57 }
58 
Generate(util::Hotfix * hotfixHelper)59 void FunctionEmitter::Generate(util::Hotfix *hotfixHelper)
60 {
61     GenFunctionKind();
62     GenIcSize();
63     GenFunctionInstructions();
64     GenVariablesDebugInfo();
65     GenSourceFileDebugInfo();
66     GenFunctionCatchTables();
67     GenLiteralBuffers();
68     if (hotfixHelper != nullptr) {
69         hotfixHelper->ProcessFunction(pg_, func_, literalBuffers_);
70     }
71 }
72 
Strings() const73 const ArenaSet<util::StringView> &FunctionEmitter::Strings() const
74 {
75     return pg_->Strings();
76 }
77 
GenFunctionKind()78 void FunctionEmitter::GenFunctionKind()
79 {
80     func_->SetFunctionKind(static_cast<panda::panda_file::FunctionKind>(pg_->GetFunctionKind()));
81 }
82 
GenIcSize()83 void FunctionEmitter::GenIcSize()
84 {
85     func_->SetSlotsNum(pg_->GetCurrentSlot());
86 }
87 
GenBufferLiterals(const LiteralBuffer * buff)88 void FunctionEmitter::GenBufferLiterals(const LiteralBuffer *buff)
89 {
90     Emitter::GenBufferLiterals(literalBuffers_, buff);
91 }
92 
SourceCode() const93 util::StringView FunctionEmitter::SourceCode() const
94 {
95     return pg_->Binder()->Program()->SourceCode();
96 }
97 
GetLineIndex() const98 lexer::LineIndex &FunctionEmitter::GetLineIndex() const
99 {
100     return const_cast<lexer::LineIndex &>(pg_->Binder()->Program()->GetLineIndex());
101 }
102 
MatchFormat(const IRNode * node,const Formats & formats)103 static Format MatchFormat(const IRNode *node, const Formats &formats)
104 {
105     std::array<const VReg *, IRNode::MAX_REG_OPERAND> regs {};
106     auto regCnt = node->Registers(&regs);
107     auto registers = Span<const VReg *>(regs.data(), regs.data() + regCnt);
108 
109     const auto *iter = formats.begin();
110 
111     for (; iter != formats.end(); iter++) {
112         auto format = *iter;
113         size_t limit = 0;
114         for (const auto &formatItem : format.GetFormatItem()) {
115             if (formatItem.IsVReg()) {
116                 limit = 1 << formatItem.Bitwidth();
117                 break;
118             }
119         }
120 
121         if (std::all_of(registers.begin(), registers.end(), [limit](const VReg *reg) { return *reg < limit; })) {
122             return format;
123         }
124     }
125 
126     UNREACHABLE();
127     return *iter;
128 }
129 
GetIRNodeWholeLength(const IRNode * node)130 static size_t GetIRNodeWholeLength(const IRNode *node)
131 {
132     Formats formats = node->GetFormats();
133     if (formats.empty()) {
134         return 0;
135     }
136 
137     size_t len = 1;
138     constexpr size_t BIT_WIDTH = 8;
139     const auto format = MatchFormat(node, formats);
140 
141     for (auto fi : format.GetFormatItem()) {
142         len += fi.Bitwidth() / BIT_WIDTH;
143     }
144 
145     return len;
146 }
147 
WholeLine(const util::StringView & source,lexer::SourceRange range)148 [[maybe_unused]] static std::string WholeLine(const util::StringView &source, lexer::SourceRange range)
149 {
150     return source.Substr(range.start.index, range.end.index).EscapeSymbol<util::StringView::Mutf8Encode>();
151 }
152 
GenInstructionDebugInfo(const IRNode * ins,panda::pandasm::Ins * pandaIns)153 void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns)
154 {
155     const ir::AstNode *astNode = ins->Node();
156     constexpr size_t INVALID_LINE = -1;
157     constexpr uint32_t INVALID_COL = -1;
158 
159     if (astNode == FIRST_NODE_OF_FUNCTION) {
160         astNode = pg_->Debuginfo().firstStmt;
161         if (!astNode) {
162             return;
163         }
164     }
165 
166     pandaIns->ins_debug.line_number = astNode ? astNode->Range().start.line : INVALID_LINE;
167 
168     if (pg_->IsDebug()) {
169         size_t insLen = GetIRNodeWholeLength(ins);
170         if (insLen != 0) {
171             pandaIns->ins_debug.bound_left = offset_;
172             pandaIns->ins_debug.bound_right = offset_ + insLen;
173         }
174 
175         offset_ += insLen;
176 
177         pandaIns->ins_debug.column_number = astNode ?
178             (GetLineIndex().GetLocation(astNode->Range().start).col - 1) : INVALID_COL;
179     }
180 }
181 
GenFunctionInstructions()182 void FunctionEmitter::GenFunctionInstructions()
183 {
184     func_->ins.reserve(pg_->Insns().size());
185 
186     for (const auto *ins : pg_->Insns()) {
187         auto &pandaIns = func_->ins.emplace_back();
188 
189         ins->Transform(&pandaIns);
190         GenInstructionDebugInfo(ins, &pandaIns);
191     }
192 
193     if (pg_->Context()->IsTypeExtractorEnabled()) {
194         TypeExtractorEmitter(pg_, func_);
195     }
196 }
197 
GenFunctionCatchTables()198 void FunctionEmitter::GenFunctionCatchTables()
199 {
200     func_->catch_blocks.reserve(pg_->CatchList().size());
201 
202     for (const auto *catchBlock : pg_->CatchList()) {
203         const auto &labelSet = catchBlock->LabelSet();
204 
205         auto &pandaCatchBlock = func_->catch_blocks.emplace_back();
206         pandaCatchBlock.try_begin_label = labelSet.TryBegin()->Id();
207         pandaCatchBlock.try_end_label = labelSet.TryEnd()->Id();
208         pandaCatchBlock.catch_begin_label = labelSet.CatchBegin()->Id();
209         pandaCatchBlock.catch_end_label = labelSet.CatchEnd()->Id();
210     }
211 }
212 
GenLiteralBuffers()213 void FunctionEmitter::GenLiteralBuffers()
214 {
215     for (const auto *buff : pg_->BuffStorage()) {
216         GenBufferLiterals(buff);
217     }
218 }
219 
GenSourceFileDebugInfo()220 void FunctionEmitter::GenSourceFileDebugInfo()
221 {
222     if (pg_->SourceFile().empty()) {
223         func_->source_file = std::string {pg_->Binder()->Program()->SourceFile()};
224     } else {
225         func_->source_file = pg_->SourceFile();
226     }
227 
228     if (!pg_->IsDebug()) {
229         return;
230     }
231 
232     if (pg_->RootNode()->IsProgram()) {
233         func_->source_code = SourceCode().Mutf8();
234     }
235 }
236 
GenScopeVariableInfo(const binder::Scope * scope)237 void FunctionEmitter::GenScopeVariableInfo(const binder::Scope *scope)
238 {
239     const auto *startIns = scope->ScopeStart();
240     const auto *endIns = scope->ScopeEnd();
241 
242     uint32_t start = 0;
243     uint32_t count = 0;
244 
245     for (const auto *it : pg_->Insns()) {
246         if (startIns == it) {
247             start = count;
248         } else if (endIns == it) {
249             auto varsLength = static_cast<uint32_t>(count - start + 1);
250 
251             for (const auto &[name, variable] : scope->Bindings()) {
252                 if (!variable->IsLocalVariable() || variable->LexicalBound()) {
253                     continue;
254                 }
255 
256                 auto &variableDebug = func_->local_variable_debug.emplace_back();
257                 variableDebug.name = name.Mutf8();
258                 variableDebug.signature = "any";
259                 variableDebug.signature_type = "any";
260                 variableDebug.reg = static_cast<int32_t>(variable->AsLocalVariable()->Vreg());
261                 variableDebug.start = start;
262                 variableDebug.length = static_cast<uint32_t>(varsLength);
263             }
264 
265             break;
266         }
267 
268         count++;
269     }
270 }
271 
GenVariablesDebugInfo()272 void FunctionEmitter::GenVariablesDebugInfo()
273 {
274     if (!pg_->IsDebug()) {
275         return;
276     }
277 
278     for (const auto *scope : pg_->Debuginfo().variableDebugInfo) {
279         GenScopeVariableInfo(scope);
280     }
281 }
282 
283 // Emitter
284 
Emitter(const CompilerContext * context)285 Emitter::Emitter(const CompilerContext *context)
286 {
287     prog_ = new panda::pandasm::Program();
288     prog_->lang = LANG_EXT;
289 
290     if (context->IsJsonInputFile()) {
291         GenJsonContentRecord(context);
292         return;
293     }
294 
295     // For Type Extractor
296     // Global record to show type extractor is enabled or not
297     GenTypeInfoRecord();
298     GenESTypeAnnotationRecord();
299 
300     if (context->IsMergeAbc()) {
301         auto recordName = context->Binder()->Program()->FormatedRecordName().Mutf8();
302         rec_ = new panda::pandasm::Record(recordName.substr(0, recordName.find_last_of('.')), LANG_EXT);
303         SetPkgNameField(context->PkgName());
304         SetCommonjsField(context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS);
305     } else {
306         rec_ = nullptr;
307         if (context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS) {
308             GenCommonjsRecord();
309         }
310     }
311 }
312 
~Emitter()313 Emitter::~Emitter()
314 {
315     delete prog_;
316 }
317 
SetPkgNameField(std::string pkgName)318 void Emitter::SetPkgNameField(std::string pkgName)
319 {
320     auto pkgNameField = panda::pandasm::Field(LANG_EXT);
321     pkgNameField.name = "pkgName@" + pkgName;
322     pkgNameField.type = panda::pandasm::Type("u8", 0);
323     pkgNameField.metadata->SetValue(
324         panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(0)));
325     rec_->field_list.emplace_back(std::move(pkgNameField));
326 }
327 
GenTypeInfoRecord() const328 void Emitter::GenTypeInfoRecord() const
329 {
330     auto typeInfoRecord = panda::pandasm::Record(TypeExtractorEmitter::TYPE_INFO_RECORD, LANG_EXT);
331     typeInfoRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
332     prog_->record_table.emplace(typeInfoRecord.name, std::move(typeInfoRecord));
333 }
334 
GenESTypeAnnotationRecord() const335 void Emitter::GenESTypeAnnotationRecord() const
336 {
337     auto typeAnnotationRecord = panda::pandasm::Record(TypeExtractorEmitter::TYPE_ANNOTATION, LANG_EXT);
338     typeAnnotationRecord.metadata->SetAttribute("external");
339     typeAnnotationRecord.metadata->SetAccessFlags(panda::ACC_ANNOTATION);
340     prog_->record_table.emplace(typeAnnotationRecord.name, std::move(typeAnnotationRecord));
341 }
342 
GenJsonContentRecord(const CompilerContext * context)343 void Emitter::GenJsonContentRecord(const CompilerContext *context)
344 {
345     rec_ = new panda::pandasm::Record(std::string(context->RecordName()), panda::panda_file::SourceLang::ECMASCRIPT);
346     auto jsonContentField = panda::pandasm::Field(panda::panda_file::SourceLang::ECMASCRIPT);
347     jsonContentField.name = "jsonFileContent";
348     jsonContentField.type = panda::pandasm::Type("u32", 0);
349     jsonContentField.metadata->SetValue(panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::STRING>(
350         static_cast<std::string_view>(context->SourceFile())));
351     rec_->field_list.emplace_back(std::move(jsonContentField));
352     if (context->HotfixHelper()) {
353         context->HotfixHelper()->ProcessJsonContentRecord(rec_->name, context->SourceFile());
354     }
355 }
356 
AddFunction(FunctionEmitter * func,CompilerContext * context)357 void Emitter::AddFunction(FunctionEmitter *func, CompilerContext *context)
358 {
359     std::lock_guard<std::mutex> lock(m_);
360 
361     for (const auto &str : func->Strings()) {
362         prog_->strings.insert(str.Mutf8());
363     }
364 
365     for (auto &[idx, buf] : func->LiteralBuffers()) {
366         auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(buf));
367         auto litId = std::string(context->Binder()->Program()->RecordName()) + "_" + std::to_string(idx);
368         prog_->literalarray_table.emplace(litId, std::move(literalArrayInstance));
369     }
370 
371     auto *function = func->Function();
372     prog_->function_table.emplace(function->name, std::move(*function));
373 }
374 
AddSourceTextModuleRecord(ModuleRecordEmitter * module,CompilerContext * context)375 void Emitter::AddSourceTextModuleRecord(ModuleRecordEmitter *module, CompilerContext *context)
376 {
377     std::lock_guard<std::mutex> lock(m_);
378 
379     auto moduleLiteral = std::string(context->Binder()->Program()->RecordName()) + "_" +
380          std::to_string(module->Index());
381     if (context->IsMergeAbc()) {
382         auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
383         moduleIdxField.name = "moduleRecordIdx";
384         moduleIdxField.type = panda::pandasm::Type("u32", 0);
385         moduleIdxField.metadata->SetValue(
386             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
387             static_cast<std::string_view>(moduleLiteral)));
388         rec_->field_list.emplace_back(std::move(moduleIdxField));
389 
390         if (context->HotfixHelper()) {
391             context->HotfixHelper()->ProcessModule(rec_->name, module->Buffer());
392         }
393     } else {
394         auto ecmaModuleRecord = panda::pandasm::Record("_ESModuleRecord", LANG_EXT);
395         ecmaModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
396 
397         auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
398         moduleIdxField.name = std::string {context->Binder()->Program()->SourceFile()};
399         moduleIdxField.type = panda::pandasm::Type("u32", 0);
400         moduleIdxField.metadata->SetValue(
401             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
402             static_cast<std::string_view>(moduleLiteral)));
403         ecmaModuleRecord.field_list.emplace_back(std::move(moduleIdxField));
404 
405         if (context->HotfixHelper()) {
406             context->HotfixHelper()->ProcessModule(ecmaModuleRecord.name, module->Buffer());
407         }
408         prog_->record_table.emplace(ecmaModuleRecord.name, std::move(ecmaModuleRecord));
409     }
410     auto &moduleLiteralsBuffer = module->Buffer();
411     auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(moduleLiteralsBuffer));
412     prog_->literalarray_table.emplace(static_cast<std::string_view>(moduleLiteral), std::move(literalArrayInstance));
413 }
414 
FillTypeInfoRecord(bool typeFlag,int64_t typeSummaryIndex) const415 void Emitter::FillTypeInfoRecord(bool typeFlag, int64_t typeSummaryIndex) const
416 {
417     TypeExtractorEmitter::GenTypeInfoRecord(prog_, typeFlag, typeSummaryIndex);
418 }
419 
FillTypeLiteralBuffers(const extractor::TypeRecorder * recorder) const420 void Emitter::FillTypeLiteralBuffers(const extractor::TypeRecorder *recorder) const
421 {
422     TypeExtractorEmitter::GenTypeLiteralBuffers(prog_, recorder);
423 }
424 
425 // static
GenBufferLiterals(ArenaVector<std::pair<int32_t,std::vector<Literal>>> & literalBuffers,const LiteralBuffer * buff)426 void Emitter::GenBufferLiterals(ArenaVector<std::pair<int32_t, std::vector<Literal>>> &literalBuffers,
427                                 const LiteralBuffer *buff)
428 {
429     auto &[idx, array] = literalBuffers.emplace_back();
430     idx = buff->Index();
431     constexpr size_t ARRAY_EXPANSION = 2;
432     array.reserve(buff->Literals().size() * ARRAY_EXPANSION);
433 
434     for (const auto *literal : buff->Literals()) {
435         panda::pandasm::LiteralArray::Literal valueLit;
436         panda::pandasm::LiteralArray::Literal tagLit;
437 
438         ir::LiteralTag tag = literal->Tag();
439 
440         switch (tag) {
441             case ir::LiteralTag::BOOLEAN: {
442                 valueLit.tag_ = panda::panda_file::LiteralTag::BOOL;
443                 valueLit.value_ = literal->GetBoolean();
444                 break;
445             }
446             case ir::LiteralTag::INTEGER: {
447                 valueLit.tag_ = panda::panda_file::LiteralTag::INTEGER;
448                 valueLit.value_ = literal->GetInt();
449                 break;
450             }
451             case ir::LiteralTag::DOUBLE: {
452                 valueLit.tag_ = panda::panda_file::LiteralTag::DOUBLE;
453                 valueLit.value_ = literal->GetDouble();
454                 break;
455             }
456             case ir::LiteralTag::STRING: {
457                 valueLit.tag_ = panda::panda_file::LiteralTag::STRING;
458                 valueLit.value_ = literal->GetString().Mutf8();
459                 break;
460             }
461             case ir::LiteralTag::ACCESSOR: {
462                 valueLit.tag_ = panda::panda_file::LiteralTag::ACCESSOR;
463                 valueLit.value_ = static_cast<uint8_t>(0);
464                 break;
465             }
466             case ir::LiteralTag::METHOD: {
467                 valueLit.tag_ = panda::panda_file::LiteralTag::METHOD;
468                 valueLit.value_ = literal->GetMethod().Mutf8();
469                 break;
470             }
471             case ir::LiteralTag::METHODAFFILIATE: {
472                 valueLit.tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE;
473                 valueLit.value_ = literal->GetMethodAffiliate();
474                 break;
475             }
476             case ir::LiteralTag::GENERATOR_METHOD: {
477                 valueLit.tag_ = panda::panda_file::LiteralTag::GENERATORMETHOD;
478                 valueLit.value_ = literal->GetMethod().Mutf8();
479                 break;
480             }
481             case ir::LiteralTag::LITERALBUFFERINDEX: {
482                 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALBUFFERINDEX;
483                 valueLit.value_ = literal->GetInt();
484                 break;
485             }
486             // TODO: support ir::LiteralTag::ASYNC_GENERATOR_METHOD
487             case ir::LiteralTag::NULL_VALUE: {
488                 valueLit.tag_ = panda::panda_file::LiteralTag::NULLVALUE;
489                 valueLit.value_ = static_cast<uint8_t>(0);
490                 break;
491             }
492             default:
493                 break;
494         }
495 
496         tagLit.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
497         tagLit.value_ = static_cast<uint8_t>(valueLit.tag_);
498 
499         array.emplace_back(tagLit);
500         array.emplace_back(valueLit);
501     }
502 }
503 
DumpAsm(const panda::pandasm::Program * prog)504 void Emitter::DumpAsm(const panda::pandasm::Program *prog)
505 {
506     auto &ss = std::cout;
507 
508     ss << ".language ECMAScript" << std::endl << std::endl;
509 
510     for (auto &[name, func] : prog->function_table) {
511         ss << ".function any " << name << '(';
512 
513         for (uint32_t i = 0; i < func.GetParamsNum(); i++) {
514             ss << "any a" << std::to_string(i);
515 
516             if (i != func.GetParamsNum() - 1) {
517                 ss << ", ";
518             }
519         }
520 
521         ss << ") {" << std::endl;
522 
523         for (const auto &ins : func.ins) {
524             ss << (ins.set_label ? "" : "\t") << ins.ToString("", true, func.GetTotalRegs()) << std::endl;
525         }
526 
527         ss << "}" << std::endl << std::endl;
528 
529         for (const auto &ct : func.catch_blocks) {
530             ss << ".catchall " << ct.try_begin_label << ", " << ct.try_end_label << ", " << ct.catch_begin_label
531                << std::endl
532                << std::endl;
533         }
534     }
535 
536     ss << std::endl;
537 }
538 
Finalize(bool dumpDebugInfo,util::Hotfix * hotfixHelper)539 panda::pandasm::Program *Emitter::Finalize(bool dumpDebugInfo, util::Hotfix *hotfixHelper)
540 {
541     if (dumpDebugInfo) {
542         debuginfo::DebugInfoDumper dumper(prog_);
543         dumper.Dump();
544     }
545 
546     if (rec_) {
547         prog_->record_table.emplace(rec_->name, std::move(*rec_));
548         delete rec_;
549         rec_ = nullptr;
550     }
551 
552     if (hotfixHelper) {
553         hotfixHelper->Finalize(&prog_);
554     }
555 
556     auto *prog = prog_;
557     prog_ = nullptr;
558     return prog;
559 }
560 }  // namespace panda::es2panda::compiler
561