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