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 
28 namespace panda::es2panda::util {
29 
30 const std::string EXTERNAL_ATTRIBUTE = "external";
31 const panda::panda_file::SourceLang SRC_LANG = panda::panda_file::SourceLang::ECMASCRIPT;
32 
ProcessFunction(const compiler::PandaGen *pg, panda::pandasm::Function *func, LiteralBuffers &literalBuffers)33 void 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 
ProcessModule(const std::string &recordName, std::vector<panda::pandasm::LiteralArray::Literal> &moduleBuffer)47 void 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 
ProcessJsonContentRecord(const std::string &recordName, const std::string &jsonFileContent)61 void 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 
DumpModuleInfo(const std::string &recordName, std::vector<panda::pandasm::LiteralArray::Literal> &moduleBuffer)74 void 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 
ValidateModuleInfo(const std::string &recordName, std::vector<panda::pandasm::LiteralArray::Literal> &moduleBuffer)83 void 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 
DumpJsonContentRecInfo(const std::string &recordName, const std::string &jsonFileContent)101 void 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 
ValidateJsonContentRecInfo(const std::string &recordName, const std::string &jsonFileContent)109 void 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 
IsAnonymousOrSpecialOrDuplicateFunction(const std::string &funcName)127 bool 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 
GetLiteralIdxFromStringId(const std::string &stringId)153 int64_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 
CollectFunctionsWithDefinedClasses(std::string funcName, std::string className)160 void 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 
GenerateFunctionAndClassHash(panda::pandasm::Function *func, LiteralBuffers &literalBuffers)171 std::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 
ConvertLiteralToString(std::vector<panda::pandasm::LiteralArray::Literal> &literalBuffer)216 std::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 
ExpandLiteral(int64_t bufferIdx, PatchFix::LiteralBuffers &literalBuffers)237 std::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 
GetLiteralMethods(int64_t bufferIdx, PatchFix::LiteralBuffers &literalBuffers)248 std::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 
CollectClassMemberFunctions(const std::string &className, int64_t bufferIdx, PatchFix::LiteralBuffers &literalBuffers)272 void 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 
IsScopeValidToPatchLexical(binder::VariableScope *scope) const280 bool 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 
AllocSlotfromPatchEnv(const std::string &variableName)298 void PatchFix::AllocSlotfromPatchEnv(const std::string &variableName)
299 {
300     if (!topScopeLexEnvs_.count(variableName)) {
301         topScopeLexEnvs_[variableName] = topScopeIdx_++;
302     }
303 }
304 
GetSlotIdFromSymbolTable(const std::string &variableName)305 uint32_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 
GetEnvSizeOfFuncMain0()318 uint32_t PatchFix::GetEnvSizeOfFuncMain0()
319 {
320     auto functionIter = originFunctionInfo_->find(funcMain0_);
321     ASSERT(functionIter != originFunctionInfo_->end());
322     return functionIter->second.lexenv.size();
323 }
324 
GetPatchLexicalIdx(const std::string &variableName)325 uint32_t PatchFix::GetPatchLexicalIdx(const std::string &variableName)
326 {
327     ASSERT(topScopeLexEnvs_.count(variableName));
328     return topScopeLexEnvs_[variableName];
329 }
330 
IsFunctionOrClassDefineIns(panda::pandasm::Ins &ins)331 bool 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 
IsStPatchVarIns(panda::pandasm::Ins &ins)341 bool IsStPatchVarIns(panda::pandasm::Ins &ins)
342 {
343     return ins.opcode == panda::pandasm::Opcode::WIDE_STPATCHVAR;
344 }
345 
CollectFuncDefineIns(panda::pandasm::Function *func)346 void 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 
HandleModifiedClasses(panda::pandasm::Program *prog)356 void 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 
HandleModifiedDefinedClassFunc(panda::pandasm::Program *prog)377 void 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 
AddHeadAndTailInsForPatchFuncMain0(std::vector<panda::pandasm::Ins> &ins)389 void 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 
AddTailInsForPatchFuncMain1(std::vector<panda::pandasm::Ins> &ins)409 void 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 
CreateFunctionPatchMain0AndMain1(panda::pandasm::Function &patchFuncMain0, panda::pandasm::Function &patchFuncMain1)416 void 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 
Finalize(panda::pandasm::Program **prog)455 void 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 
CompareLexenv(const std::string &funcName, const compiler::PandaGen *pg, SymbolTable::OriginFunctionInfo &bytecodeInfo)483 bool 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 
CompareClassHash(std::vector<std::pair<std::string, std::string>> &hashList, SymbolTable::OriginFunctionInfo &bytecodeInfo)518 bool 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 
CheckAndRestoreSpecialFunctionName(uint32_t globalIndexForSpecialFunc, std::string &funcInternalName, std::string recordName)540 void 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 
HandleFunction(const compiler::PandaGen *pg, panda::pandasm::Function *func, LiteralBuffers &literalBuffers)565 void 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 
DumpFunctionInfo(const compiler::PandaGen *pg, panda::pandasm::Function *func, PatchFix::LiteralBuffers &literalBuffers)617 void 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 
IsAdditionalVarInPatch(uint32_t slot)655 bool PatchFix::IsAdditionalVarInPatch(uint32_t slot)
656 {
657     return slot == UINT32_MAX;
658 }
659 
IsDumpSymbolTable() const660 bool PatchFix::IsDumpSymbolTable() const
661 {
662     return patchFixKind_ == PatchFixKind::DUMPSYMBOLTABLE;
663 }
664 
IsHotFix() const665 bool PatchFix::IsHotFix() const
666 {
667     return patchFixKind_ == PatchFixKind::HOTFIX;
668 }
669 
IsColdFix() const670 bool PatchFix::IsColdFix() const
671 {
672     return patchFixKind_ == PatchFixKind::COLDFIX;
673 }
674 
IsHotReload() const675 bool PatchFix::IsHotReload() const
676 {
677     return patchFixKind_ == PatchFixKind::HOTRELOAD;
678 }
679 
IsColdReload() const680 bool PatchFix::IsColdReload() const
681 {
682     return patchFixKind_ == PatchFixKind::COLDRELOAD;
683 }
684 
685 } // namespace panda::es2panda::util
686