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