1/*
2 * Copyright (c) 2022 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 "patchFix.h"
17#include <binder/binder.h>
18#include <binder/scope.h>
19#include <binder/variable.h>
20#include <compiler/core/pandagen.h>
21#include <ir/expressions/literal.h>
22
23#include <fstream>
24#include <iostream>
25#include <string>
26#include <unistd.h>
27
28namespace panda::es2panda::util {
29
30const std::string EXTERNAL_ATTRIBUTE = "external";
31const panda::panda_file::SourceLang SRC_LANG = panda::panda_file::SourceLang::ECMASCRIPT;
32
33void PatchFix::ProcessFunction(const compiler::PandaGen *pg, panda::pandasm::Function *func,
34    LiteralBuffers &literalBuffers)
35{
36    if (generateSymbolFile_) {
37        DumpFunctionInfo(pg, func, literalBuffers);
38        return;
39    }
40
41    if (generatePatch_ || IsHotReload()) {
42        HandleFunction(pg, func, literalBuffers);
43        return;
44    }
45}
46
47void PatchFix::ProcessModule(const std::string &recordName,
48    std::vector<panda::pandasm::LiteralArray::Literal> &moduleBuffer)
49{
50    if (generateSymbolFile_) {
51        DumpModuleInfo(recordName, moduleBuffer);
52        return;
53    }
54
55    if (generatePatch_ || IsHotReload()) {
56        ValidateModuleInfo(recordName, moduleBuffer);
57        return;
58    }
59}
60
61void PatchFix::ProcessJsonContentRecord(const std::string &recordName, const std::string &jsonFileContent)
62{
63    if (generateSymbolFile_) {
64        DumpJsonContentRecInfo(recordName, jsonFileContent);
65        return;
66    }
67
68    if (generatePatch_ || IsHotReload()) {
69        ValidateJsonContentRecInfo(recordName, jsonFileContent);
70        return;
71    }
72}
73
74void PatchFix::DumpModuleInfo(const std::string &recordName,
75    std::vector<panda::pandasm::LiteralArray::Literal> &moduleBuffer)
76{
77    std::stringstream ss;
78    ss << recordName << SymbolTable::SECOND_LEVEL_SEPERATOR;
79    ss << Helpers::GetHashString(ConvertLiteralToString(moduleBuffer)) << std::endl;
80    symbolTable_->FillSymbolTable(ss);
81}
82
83void PatchFix::ValidateModuleInfo(const std::string &recordName,
84    std::vector<panda::pandasm::LiteralArray::Literal> &moduleBuffer)
85{
86    auto it = originModuleInfo_->find(recordName);
87    if (!IsHotReload() && it == originModuleInfo_->end()) {
88        std::cerr << "[Patch] Found new import/export expression in " << recordName << ", not supported!" << std::endl;
89        patchError_ = true;
90        return;
91    }
92
93    if (!IsHotReload() && Helpers::GetHashString(ConvertLiteralToString(moduleBuffer)) != it->second) {
94        std::cerr << "[Patch] Found import/export expression changed in " << recordName << ", not supported!" <<
95            std::endl;
96        patchError_ = true;
97        return;
98    }
99}
100
101void PatchFix::DumpJsonContentRecInfo(const std::string &recordName, const std::string &jsonFileContent)
102{
103    std::stringstream ss;
104    ss << recordName << SymbolTable::SECOND_LEVEL_SEPERATOR;
105    ss << Helpers::GetHashString(jsonFileContent) << std::endl;
106    symbolTable_->FillSymbolTable(ss);
107}
108
109void PatchFix::ValidateJsonContentRecInfo(const std::string &recordName, const std::string &jsonFileContent)
110{
111    auto it = originModuleInfo_->find(recordName);
112    if (!IsHotReload() && it == originModuleInfo_->end()) {
113        std::cerr << "[Patch] Found new import/require json file expression in " << recordName <<
114            ", not supported!" << std::endl;
115        patchError_ = true;
116        return;
117    }
118
119    if (!IsHotReload() && Helpers::GetHashString(jsonFileContent) != it->second) {
120        std::cerr << "[Patch] Found imported/required json file content changed in " << recordName <<
121            ", not supported!" << std::endl;
122        patchError_ = true;
123        return;
124    }
125}
126
127bool PatchFix::IsAnonymousOrSpecialOrDuplicateFunction(const std::string &funcName)
128{
129    if (util::Helpers::IsDefaultApiVersion(targetApiVersion_, targetApiSubVersion_)) {
130        return funcName.find(binder::Binder::ANONYMOUS_SPECIAL_DUPLICATE_FUNCTION_SPECIFIER) != std::string::npos;
131    }
132    // Function name is like: #scopes^1#functionname^1
133    // Special function name is which includes "\\" or ".", the name should be transformed into "".
134    // Anonymous function name is "", it's the same with special function name here.
135    // Duplicate function name includes "^" after the last "#".
136    auto pos = funcName.find_last_of(Helpers::FUNC_NAME_SEPARATOR);
137    if (pos == std::string::npos) {
138        return false;
139    }
140
141    if (pos == funcName.size() - 1) {
142        return true;
143    }
144
145    auto posOfDuplicateSep = funcName.find_last_of(Helpers::DUPLICATED_SEPERATOR);
146    if (posOfDuplicateSep != std::string::npos && posOfDuplicateSep > pos) {
147        return true;
148    }
149
150    return false;
151}
152
153int64_t PatchFix::GetLiteralIdxFromStringId(const std::string &stringId)
154{
155    auto recordPrefix = recordName_ + "_";
156    auto idxStr = stringId.substr(recordPrefix.size());
157    return std::atoi(idxStr.c_str());
158}
159
160void PatchFix::CollectFunctionsWithDefinedClasses(std::string funcName, std::string className)
161{
162    auto funcInfo = funcDefinedClasses_.find(funcName);
163    if (funcInfo != funcDefinedClasses_.end()) {
164        funcInfo->second.push_back(className);
165        return;
166    }
167    std::vector<std::string> funcDefinedClasses = {className};
168    funcDefinedClasses_.insert({funcName, funcDefinedClasses});
169}
170
171std::vector<std::pair<std::string, std::string>> PatchFix::GenerateFunctionAndClassHash(panda::pandasm::Function *func,
172    LiteralBuffers &literalBuffers)
173{
174    std::stringstream ss;
175    std::vector<std::pair<std::string, std::string>> hashList;
176
177    ss << ".function any " << func->name << '(';
178
179    for (uint32_t i = 0; i < func->GetParamsNum(); i++) {
180        ss << "any a" << std::to_string(i);
181        if (i != func->GetParamsNum() - 1) {
182            ss << ", ";
183        }
184    }
185    ss << ") {" << std::endl;
186
187    for (const auto &ins : func->ins) {
188        ss << (ins.set_label ? "" : "\t") << ins.ToString("", true, func->GetTotalRegs()) << " ";
189        if (ins.opcode == panda::pandasm::Opcode::CREATEARRAYWITHBUFFER ||
190            ins.opcode == panda::pandasm::Opcode::CREATEOBJECTWITHBUFFER) {
191            int64_t bufferIdx = GetLiteralIdxFromStringId(ins.ids[0]);
192            ss << ExpandLiteral(bufferIdx, literalBuffers) << " ";
193        } else if (ins.opcode == panda::pandasm::Opcode::DEFINECLASSWITHBUFFER) {
194            CollectFunctionsWithDefinedClasses(func->name, ins.ids[0]);
195            int64_t bufferIdx = GetLiteralIdxFromStringId(ins.ids[1]);
196            std::string literalStr = ExpandLiteral(bufferIdx, literalBuffers);
197            auto classHash = Helpers::GetHashString(literalStr);
198            hashList.push_back(std::pair<std::string, std::string>(ins.ids[0], classHash));
199            CollectClassMemberFunctions(ins.ids[0], bufferIdx, literalBuffers);
200        }
201        ss << " ";
202    }
203
204    ss << "}" << std::endl;
205
206    for (const auto &ct : func->catch_blocks) {
207        ss << ".catchall " << ct.try_begin_label << ", " << ct.try_end_label << ", " << ct.catch_begin_label
208            << std::endl;
209    }
210
211    auto funcHash = Helpers::GetHashString(ss.str());
212    hashList.push_back(std::pair<std::string, std::string>(func->name, funcHash));
213    return hashList;
214}
215
216std::string PatchFix::ConvertLiteralToString(std::vector<panda::pandasm::LiteralArray::Literal> &literalBuffer)
217{
218    std::stringstream ss;
219    int count = 0;
220    for (auto &literal : literalBuffer) {
221        ss << "{" << "index: " << count++ << " ";
222        ss << "tag: " << static_cast<std::underlying_type<panda::es2panda::ir::LiteralTag>::type>(literal.tag_);
223        ss << " ";
224        std::string val;
225        std::visit([&val](auto&& element) {
226            val += "val: ";
227            val += element;
228            val += " ";
229        }, literal.value_);
230        ss << val;
231        ss << "},";
232    }
233
234    return ss.str();
235}
236
237std::string PatchFix::ExpandLiteral(int64_t bufferIdx, PatchFix::LiteralBuffers &literalBuffers)
238{
239    for (auto &litPair : literalBuffers) {
240        if (litPair.first == bufferIdx) {
241            return ConvertLiteralToString(litPair.second);
242        }
243    }
244
245    return "";
246}
247
248std::vector<std::string> PatchFix::GetLiteralMethods(int64_t bufferIdx, PatchFix::LiteralBuffers &literalBuffers)
249{
250    std::vector<std::string> methods;
251    for (auto &litPair : literalBuffers) {
252        if (litPair.first != bufferIdx) {
253            continue;
254        }
255        for (auto &literal : litPair.second) {
256            switch (literal.tag_) {
257                case panda::panda_file::LiteralTag::METHOD:
258                case panda::panda_file::LiteralTag::GENERATORMETHOD:
259                case panda::panda_file::LiteralTag::ASYNCGENERATORMETHOD: {
260                    methods.push_back(std::get<std::string>(literal.value_));
261                    break;
262                }
263                default:
264                    break;
265            }
266        }
267    }
268
269    return methods;
270}
271
272void PatchFix::CollectClassMemberFunctions(const std::string &className, int64_t bufferIdx,
273    PatchFix::LiteralBuffers &literalBuffers)
274{
275    std::vector<std::string> classMemberFunctions = GetLiteralMethods(bufferIdx, literalBuffers);
276    classMemberFunctions.push_back(className);
277    classMemberFunctions_.insert({className, classMemberFunctions});
278}
279
280bool PatchFix::IsScopeValidToPatchLexical(binder::VariableScope *scope) const
281{
282    if (IsDumpSymbolTable()) {
283        return false;
284    }
285
286    CHECK_NOT_NULL(scope);
287    if (!scope->IsFunctionVariableScope()) {
288        return false;
289    }
290
291    auto funcName = scope->AsFunctionVariableScope()->InternalName();
292    if (std::string(funcName) != funcMain0_) {
293        return false;
294    }
295    return true;
296}
297
298void PatchFix::AllocSlotfromPatchEnv(const std::string &variableName)
299{
300    if (!topScopeLexEnvs_.count(variableName)) {
301        topScopeLexEnvs_[variableName] = topScopeIdx_++;
302    }
303}
304
305uint32_t PatchFix::GetSlotIdFromSymbolTable(const std::string &variableName)
306{
307    auto functionIter = originFunctionInfo_->find(funcMain0_);
308    if (functionIter != originFunctionInfo_->end()) {
309        for (const auto &lexenv : functionIter->second.lexenv) {
310            if (lexenv.second.first == variableName) {
311                return lexenv.first;
312            }
313        }
314    }
315    return UINT32_MAX;
316}
317
318uint32_t PatchFix::GetEnvSizeOfFuncMain0()
319{
320    auto functionIter = originFunctionInfo_->find(funcMain0_);
321    ASSERT(functionIter != originFunctionInfo_->end());
322    return functionIter->second.lexenv.size();
323}
324
325uint32_t PatchFix::GetPatchLexicalIdx(const std::string &variableName)
326{
327    ASSERT(topScopeLexEnvs_.count(variableName));
328    return topScopeLexEnvs_[variableName];
329}
330
331bool IsFunctionOrClassDefineIns(panda::pandasm::Ins &ins)
332{
333    if (ins.opcode == panda::pandasm::Opcode::DEFINEMETHOD ||
334        ins.opcode == panda::pandasm::Opcode::DEFINEFUNC ||
335        ins.opcode == panda::pandasm::Opcode::DEFINECLASSWITHBUFFER) {
336        return true;
337    }
338    return false;
339}
340
341bool IsStPatchVarIns(panda::pandasm::Ins &ins)
342{
343    return ins.opcode == panda::pandasm::Opcode::WIDE_STPATCHVAR;
344}
345
346void PatchFix::CollectFuncDefineIns(panda::pandasm::Function *func)
347{
348    for (size_t i = 0; i < func->ins.size(); ++i) {
349        if (IsFunctionOrClassDefineIns(func->ins[i])) {
350            funcDefineIns_.push_back(func->ins[i]);  // push define ins
351            funcDefineIns_.push_back(func->ins[i + 1]);  // push store ins
352        }
353    }
354}
355
356void PatchFix::HandleModifiedClasses(panda::pandasm::Program *prog)
357{
358    for (auto &cls: classMemberFunctions_) {
359        for (auto &func: cls.second) {
360            if (!prog->function_table.at(func).metadata->IsForeign()) {
361                modifiedClassNames_.insert(cls.first);
362                break;
363            }
364        }
365    }
366
367    for (auto &cls: modifiedClassNames_) {
368        auto &memberFunctions = classMemberFunctions_[cls];
369        for (auto &func: memberFunctions) {
370            if (prog->function_table.at(func).metadata->IsForeign()) {
371                prog->function_table.at(func).metadata->RemoveAttribute(EXTERNAL_ATTRIBUTE);
372            }
373        }
374    }
375}
376
377void PatchFix::HandleModifiedDefinedClassFunc(panda::pandasm::Program *prog)
378{
379    for (auto &funcInfo: funcDefinedClasses_) {
380        for (auto &definedClass: funcInfo.second) {
381            if (modifiedClassNames_.count(definedClass) &&
382                prog->function_table.at(funcInfo.first).metadata->IsForeign()) {
383                prog->function_table.at(funcInfo.first).metadata->RemoveAttribute(EXTERNAL_ATTRIBUTE);
384            }
385        }
386    }
387}
388
389void PatchFix::AddHeadAndTailInsForPatchFuncMain0(std::vector<panda::pandasm::Ins> &ins)
390{
391    panda::pandasm::Ins returnUndefine;
392    returnUndefine.opcode = pandasm::Opcode::RETURNUNDEFINED;
393
394    if (ins.size() == 0) {
395        ins.push_back(returnUndefine);
396        return;
397    }
398
399    panda::pandasm::Ins newLexenv;
400    newLexenv.opcode = pandasm::Opcode::NEWLEXENV;
401    newLexenv.imms.reserve(1);
402    auto newFuncNum = long(ins.size() / 2);  // each new function has 2 ins: define and store
403    newLexenv.imms.emplace_back(newFuncNum);
404
405    ins.insert(ins.begin(), newLexenv);
406    ins.push_back(returnUndefine);
407}
408
409void PatchFix::AddTailInsForPatchFuncMain1(std::vector<panda::pandasm::Ins> &ins)
410{
411    panda::pandasm::Ins returnUndefined;
412    returnUndefined.opcode = pandasm::Opcode::RETURNUNDEFINED;
413    ins.push_back(returnUndefined);
414}
415
416void PatchFix::CreateFunctionPatchMain0AndMain1(panda::pandasm::Function &patchFuncMain0,
417    panda::pandasm::Function &patchFuncMain1)
418{
419    const size_t defaultParamCount = 3;
420    patchFuncMain0.params.reserve(defaultParamCount);
421    patchFuncMain1.params.reserve(defaultParamCount);
422    for (uint32_t i = 0; i < defaultParamCount; ++i) {
423        patchFuncMain0.params.emplace_back(panda::pandasm::Type("any", 0), SRC_LANG);
424        patchFuncMain1.params.emplace_back(panda::pandasm::Type("any", 0), SRC_LANG);
425    }
426
427    std::vector<panda::pandasm::Ins> patchMain0DefineIns;
428    std::vector<panda::pandasm::Ins> patchMain1DefineIns;
429
430    for (size_t i = 0; i < funcDefineIns_.size(); ++i) {
431        if (IsFunctionOrClassDefineIns(funcDefineIns_[i])) {
432            auto &name = funcDefineIns_[i].ids[0];
433            if (newFuncNames_.count(name) && IsStPatchVarIns(funcDefineIns_[i + 1])) {
434                patchMain0DefineIns.push_back(funcDefineIns_[i]);
435                patchMain0DefineIns.push_back(funcDefineIns_[i + 1]);
436                continue;
437            }
438            if (patchFuncNames_.count(name) || modifiedClassNames_.count(name)) {
439                patchMain1DefineIns.push_back(funcDefineIns_[i]);
440                continue;
441            }
442        }
443    }
444
445    AddHeadAndTailInsForPatchFuncMain0(patchMain0DefineIns);
446    AddTailInsForPatchFuncMain1(patchMain1DefineIns);
447
448    patchFuncMain0.ins = patchMain0DefineIns;
449    patchFuncMain1.ins = patchMain1DefineIns;
450
451    patchFuncMain0.return_type = panda::pandasm::Type("any", 0);
452    patchFuncMain1.return_type = panda::pandasm::Type("any", 0);
453}
454
455void PatchFix::Finalize(panda::pandasm::Program **prog)
456{
457    if (IsDumpSymbolTable() || IsColdReload()) {
458        return;
459    }
460
461    HandleModifiedClasses(*prog);
462
463    HandleModifiedDefinedClassFunc(*prog);
464
465    if (patchError_) {
466        *prog = nullptr;
467        std::cerr << "[Patch] Found unsupported change in file, will not generate patch!" << std::endl;
468        return;
469    }
470
471    if (IsHotReload() || IsColdFix()) {
472        return;
473    }
474
475    panda::pandasm::Function patchFuncMain0(patchMain0_, SRC_LANG);
476    panda::pandasm::Function patchFuncMain1(patchMain1_, SRC_LANG);
477    CreateFunctionPatchMain0AndMain1(patchFuncMain0, patchFuncMain1);
478
479    (*prog)->function_table.emplace(patchFuncMain0.name, std::move(patchFuncMain0));
480    (*prog)->function_table.emplace(patchFuncMain1.name, std::move(patchFuncMain1));
481}
482
483bool PatchFix::CompareLexenv(const std::string &funcName, const compiler::PandaGen *pg,
484    SymbolTable::OriginFunctionInfo &bytecodeInfo)
485{
486    auto &lexicalVarNameAndTypes = pg->TopScope()->GetLexicalVarNameAndTypes();
487    auto &lexenv = bytecodeInfo.lexenv;
488    if (funcName != funcMain0_) {
489        if (lexenv.size() != lexicalVarNameAndTypes.size()) {
490            std::cerr << "[Patch] Found lexical variable added or removed in " << funcName << ", not supported!"
491                << std::endl;
492            patchError_ = true;
493            return false;
494        }
495        for (auto &variable: lexicalVarNameAndTypes) {
496            auto varSlot = variable.first;
497            auto lexenvIter = lexenv.find(varSlot);
498            if (lexenvIter == lexenv.end()) {
499                std::cerr << "[Patch] Found new lexical variable added in function " << funcName << ", not supported!"
500                    << std::endl;
501                patchError_ = true;
502                return false;
503            }
504
505            auto &lexInfo = lexenvIter->second;
506            if (!IsColdFix() && (std::string(variable.second.first) != lexInfo.first ||
507                                 variable.second.second != lexInfo.second)) {
508                std::cerr << "[Patch] Found lexical variable changed in function " << funcName << ", not supported!"
509                    << std::endl;
510                patchError_ = true;
511                return false;
512            }
513        }
514    }
515    return true;
516}
517
518bool PatchFix::CompareClassHash(std::vector<std::pair<std::string, std::string>> &hashList,
519    SymbolTable::OriginFunctionInfo &bytecodeInfo)
520{
521    auto &classInfo = bytecodeInfo.classHash;
522    for (size_t i = 0; i < hashList.size() - 1; ++i) {
523        auto &className = hashList[i].first;
524        auto classIter = classInfo.find(className);
525        if (!IsHotReload() && classIter != classInfo.end() && classIter->second != hashList[i].second) {
526            if (IsColdFix()) {
527                modifiedClassNames_.insert(className);
528                continue;
529            } else {
530                ASSERT(IsHotFix());
531                std::cerr << "[Patch] Found class " << hashList[i].first << " changed, not supported!" << std::endl;
532            }
533            patchError_ = true;
534            return false;
535        }
536    }
537    return true;
538}
539
540void PatchFix::CheckAndRestoreSpecialFunctionName(uint32_t globalIndexForSpecialFunc, std::string &funcInternalName,
541    std::string recordName)
542{
543    auto it = originRecordHashFunctionNames_->find(recordName);
544    if (it != originRecordHashFunctionNames_->end()) {
545        if (it->second.size() == 0 || globalIndexForSpecialFunc > it->second.size()) {
546            // anonymous, special or duplicate function added
547            std::cerr << "[Patch] Found new anonymous, special(containing '.' or '\\') or duplicate name function "
548                    << funcInternalName << " not supported!" << std::endl;
549            patchError_ = true;
550            return;
551        }
552        std::string originalName = it->second.at(std::to_string(globalIndexForSpecialFunc));
553        // special name function in the same position must have the same real function name as original
554        if (originalName.substr(originalName.find_last_of("#")) !=
555            funcInternalName.substr(funcInternalName.find_last_of("#"))) {
556            std::cerr << "[Patch] Found new anonymous, special(containing '.' or '\\') or duplicate name function "
557                    << funcInternalName << " not supported!" << std::endl;
558            patchError_ = true;
559            return;
560        }
561        funcInternalName = originalName;
562    }
563}
564
565void PatchFix::HandleFunction(const compiler::PandaGen *pg, panda::pandasm::Function *func,
566    LiteralBuffers &literalBuffers)
567{
568    std::string funcName = func->name;
569    auto originFunction = originFunctionInfo_->find(funcName);
570    if (originFunction == originFunctionInfo_->end()) {
571        if ((!util::Helpers::IsDefaultApiVersion(targetApiVersion_, targetApiSubVersion_)) &&
572            IsHotFix() &&
573            IsAnonymousOrSpecialOrDuplicateFunction(funcName)) {
574            std::cerr << "[Patch] Found new anonymous, special(containing '.' or '\\') or duplicate name function "
575                      << funcName << " not supported!" << std::endl;
576            patchError_ = true;
577            return;
578        }
579        newFuncNames_.insert(funcName);
580        CollectFuncDefineIns(func);
581        return;
582    }
583
584    auto &bytecodeInfo = originFunction->second;
585    if (!CompareLexenv(funcName, pg, bytecodeInfo)) {
586        return;
587    }
588
589    auto hashList = GenerateFunctionAndClassHash(func, literalBuffers);
590    if (!CompareClassHash(hashList, bytecodeInfo)) {
591        return;
592    }
593
594    if (IsHotReload()) {
595        return;
596    }
597
598    auto funcHash = hashList.back().second;
599
600    if (funcName == funcMain0_) {
601        if (IsHotFix()) {
602            func->metadata->SetAttribute(EXTERNAL_ATTRIBUTE);
603        } else {
604            patchFuncNames_.insert(funcName);
605        }
606    } else {
607        if (funcHash == bytecodeInfo.funcHash) {
608            func->metadata->SetAttribute(EXTERNAL_ATTRIBUTE);
609        } else {
610            patchFuncNames_.insert(funcName);
611        }
612    }
613
614    CollectFuncDefineIns(func);
615}
616
617void PatchFix::DumpFunctionInfo(const compiler::PandaGen *pg, panda::pandasm::Function *func,
618    PatchFix::LiteralBuffers &literalBuffers)
619{
620    std::stringstream ss;
621
622    ss << pg->InternalName();
623    ss << SymbolTable::SECOND_LEVEL_SEPERATOR << pg->InternalName() << SymbolTable::SECOND_LEVEL_SEPERATOR;
624
625    std::vector<std::pair<std::string, std::string>> hashList = GenerateFunctionAndClassHash(func, literalBuffers);
626    ss << hashList.back().second << SymbolTable::SECOND_LEVEL_SEPERATOR;
627
628    if (util::Helpers::IsDefaultApiVersion(targetApiVersion_, targetApiSubVersion_)) {
629        auto internalNameStr = pg->InternalName().Mutf8();
630        if (internalNameStr.find("#") != std::string::npos) {
631            ss << (pg->Binder()->SpecialFuncNameIndexMap()).at(internalNameStr) << SymbolTable::SECOND_LEVEL_SEPERATOR;
632        } else {
633            // index 0 for all the normal name functions
634            ss << "0" << SymbolTable::SECOND_LEVEL_SEPERATOR;
635        }
636    }
637
638    ss << SymbolTable::FIRST_LEVEL_SEPERATOR;
639    for (size_t i = 0; i < hashList.size() - 1; ++i) {
640        ss << hashList[i].first << SymbolTable::SECOND_LEVEL_SEPERATOR << hashList[i].second <<
641            SymbolTable::SECOND_LEVEL_SEPERATOR;
642    }
643    ss << SymbolTable::SECOND_LEVEL_SEPERATOR << SymbolTable::FIRST_LEVEL_SEPERATOR;
644
645    for (auto &variable: pg->TopScope()->GetLexicalVarNameAndTypes()) {
646        ss << variable.second.first << SymbolTable::SECOND_LEVEL_SEPERATOR
647           << variable.first << SymbolTable::SECOND_LEVEL_SEPERATOR
648           << variable.second.second << SymbolTable::SECOND_LEVEL_SEPERATOR;
649    }
650    ss << SymbolTable::SECOND_LEVEL_SEPERATOR << std::endl;
651
652    symbolTable_->FillSymbolTable(ss);
653}
654
655bool PatchFix::IsAdditionalVarInPatch(uint32_t slot)
656{
657    return slot == UINT32_MAX;
658}
659
660bool PatchFix::IsDumpSymbolTable() const
661{
662    return patchFixKind_ == PatchFixKind::DUMPSYMBOLTABLE;
663}
664
665bool PatchFix::IsHotFix() const
666{
667    return patchFixKind_ == PatchFixKind::HOTFIX;
668}
669
670bool PatchFix::IsColdFix() const
671{
672    return patchFixKind_ == PatchFixKind::COLDFIX;
673}
674
675bool PatchFix::IsHotReload() const
676{
677    return patchFixKind_ == PatchFixKind::HOTRELOAD;
678}
679
680bool PatchFix::IsColdReload() const
681{
682    return patchFixKind_ == PatchFixKind::COLDRELOAD;
683}
684
685} // namespace panda::es2panda::util
686