• 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 <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_->WriteSymbolTable(ss.str());
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_->WriteSymbolTable(ss.str());
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     return funcName.find(binder::Binder::ANONYMOUS_SPECIAL_DUPLICATE_FUNCTION_SPECIFIER) != std::string::npos;
130 }
131 
GetLiteralIdxFromStringId(const std::string & stringId)132 int64_t PatchFix::GetLiteralIdxFromStringId(const std::string &stringId)
133 {
134     auto recordPrefix = recordName_ + "_";
135     auto idxStr = stringId.substr(recordPrefix.size());
136     return std::atoi(idxStr.c_str());
137 }
138 
CollectFunctionsWithDefinedClasses(std::string funcName,std::string className)139 void PatchFix::CollectFunctionsWithDefinedClasses(std::string funcName, std::string className)
140 {
141     auto funcInfo = funcDefinedClasses_.find(funcName);
142     if (funcInfo != funcDefinedClasses_.end()) {
143         funcInfo->second.push_back(className);
144         return;
145     }
146     std::vector<std::string> funcDefinedClasses = {className};
147     funcDefinedClasses_.insert({funcName, funcDefinedClasses});
148 }
149 
GenerateFunctionAndClassHash(panda::pandasm::Function * func,LiteralBuffers & literalBuffers)150 std::vector<std::pair<std::string, std::string>> PatchFix::GenerateFunctionAndClassHash(panda::pandasm::Function *func,
151     LiteralBuffers &literalBuffers)
152 {
153     std::stringstream ss;
154     std::vector<std::pair<std::string, std::string>> hashList;
155 
156     ss << ".function any " << func->name << '(';
157 
158     for (uint32_t i = 0; i < func->GetParamsNum(); i++) {
159         ss << "any a" << std::to_string(i);
160         if (i != func->GetParamsNum() - 1) {
161             ss << ", ";
162         }
163     }
164     ss << ") {" << std::endl;
165 
166     for (const auto &ins : func->ins) {
167         ss << (ins.set_label ? "" : "\t") << ins.ToString("", true, func->GetTotalRegs()) << " ";
168         if (ins.opcode == panda::pandasm::Opcode::CREATEARRAYWITHBUFFER ||
169             ins.opcode == panda::pandasm::Opcode::CREATEOBJECTWITHBUFFER) {
170             int64_t bufferIdx = GetLiteralIdxFromStringId(ins.ids[0]);
171             ss << ExpandLiteral(bufferIdx, literalBuffers) << " ";
172         } else if (ins.opcode == panda::pandasm::Opcode::DEFINECLASSWITHBUFFER) {
173             CollectFunctionsWithDefinedClasses(func->name, ins.ids[0]);
174             int64_t bufferIdx = GetLiteralIdxFromStringId(ins.ids[1]);
175             std::string literalStr = ExpandLiteral(bufferIdx, literalBuffers);
176             auto classHash = Helpers::GetHashString(literalStr);
177             hashList.push_back(std::pair<std::string, std::string>(ins.ids[0], classHash));
178             CollectClassMemberFunctions(ins.ids[0], bufferIdx, literalBuffers);
179         }
180         ss << " ";
181     }
182 
183     ss << "}" << std::endl;
184 
185     for (const auto &ct : func->catch_blocks) {
186         ss << ".catchall " << ct.try_begin_label << ", " << ct.try_end_label << ", " << ct.catch_begin_label
187             << std::endl;
188     }
189 
190     auto funcHash = Helpers::GetHashString(ss.str());
191     hashList.push_back(std::pair<std::string, std::string>(func->name, funcHash));
192     return hashList;
193 }
194 
ConvertLiteralToString(std::vector<panda::pandasm::LiteralArray::Literal> & literalBuffer)195 std::string PatchFix::ConvertLiteralToString(std::vector<panda::pandasm::LiteralArray::Literal> &literalBuffer)
196 {
197     std::stringstream ss;
198     int count = 0;
199     for (auto &literal : literalBuffer) {
200         ss << "{" << "index: " << count++ << " ";
201         ss << "tag: " << static_cast<std::underlying_type<panda::es2panda::ir::LiteralTag>::type>(literal.tag_);
202         ss << " ";
203         std::string val;
204         std::visit([&val](auto&& element) {
205             val += "val: ";
206             val += element;
207             val += " ";
208         }, literal.value_);
209         ss << val;
210         ss << "},";
211     }
212 
213     return ss.str();
214 }
215 
ExpandLiteral(int64_t bufferIdx,PatchFix::LiteralBuffers & literalBuffers)216 std::string PatchFix::ExpandLiteral(int64_t bufferIdx, PatchFix::LiteralBuffers &literalBuffers)
217 {
218     for (auto &litPair : literalBuffers) {
219         if (litPair.first == bufferIdx) {
220             return ConvertLiteralToString(litPair.second);
221         }
222     }
223 
224     return "";
225 }
226 
GetLiteralMethods(int64_t bufferIdx,PatchFix::LiteralBuffers & literalBuffers)227 std::vector<std::string> PatchFix::GetLiteralMethods(int64_t bufferIdx, PatchFix::LiteralBuffers &literalBuffers)
228 {
229     std::vector<std::string> methods;
230     for (auto &litPair : literalBuffers) {
231         if (litPair.first != bufferIdx) {
232             continue;
233         }
234         for (auto &literal : litPair.second) {
235             switch (literal.tag_) {
236                 case panda::panda_file::LiteralTag::METHOD:
237                 case panda::panda_file::LiteralTag::GENERATORMETHOD:
238                 case panda::panda_file::LiteralTag::ASYNCGENERATORMETHOD: {
239                     methods.push_back(std::get<std::string>(literal.value_));
240                     break;
241                 }
242                 default:
243                     break;
244             }
245         }
246     }
247 
248     return methods;
249 }
250 
CollectClassMemberFunctions(const std::string & className,int64_t bufferIdx,PatchFix::LiteralBuffers & literalBuffers)251 void PatchFix::CollectClassMemberFunctions(const std::string &className, int64_t bufferIdx,
252     PatchFix::LiteralBuffers &literalBuffers)
253 {
254     std::vector<std::string> classMemberFunctions = GetLiteralMethods(bufferIdx, literalBuffers);
255     classMemberFunctions.push_back(className);
256     classMemberFunctions_.insert({className, classMemberFunctions});
257 }
258 
IsScopeValidToPatchLexical(binder::VariableScope * scope) const259 bool PatchFix::IsScopeValidToPatchLexical(binder::VariableScope *scope) const
260 {
261     if (IsDumpSymbolTable()) {
262         return false;
263     }
264 
265     if (!scope->IsFunctionVariableScope()) {
266         return false;
267     }
268 
269     auto funcName = scope->AsFunctionVariableScope()->InternalName();
270     if (std::string(funcName) != funcMain0_) {
271         return false;
272     }
273     return true;
274 }
275 
AllocSlotfromPatchEnv(const std::string & variableName)276 void PatchFix::AllocSlotfromPatchEnv(const std::string &variableName)
277 {
278     if (!topScopeLexEnvs_.count(variableName)) {
279         topScopeLexEnvs_[variableName] = topScopeIdx_++;
280     }
281 }
282 
GetSlotIdFromSymbolTable(const std::string & variableName)283 uint32_t PatchFix::GetSlotIdFromSymbolTable(const std::string &variableName)
284 {
285     auto functionIter = originFunctionInfo_->find(funcMain0_);
286     if (functionIter != originFunctionInfo_->end()) {
287         for (const auto &lexenv : functionIter->second.lexenv) {
288             if (lexenv.second.first == variableName) {
289                 return lexenv.first;
290             }
291         }
292     }
293     return UINT32_MAX;
294 }
295 
GetEnvSizeOfFuncMain0()296 uint32_t PatchFix::GetEnvSizeOfFuncMain0()
297 {
298     auto functionIter = originFunctionInfo_->find(funcMain0_);
299     ASSERT(functionIter != originFunctionInfo_->end());
300     return functionIter->second.lexenv.size();
301 }
302 
GetPatchLexicalIdx(const std::string & variableName)303 uint32_t PatchFix::GetPatchLexicalIdx(const std::string &variableName)
304 {
305     ASSERT(topScopeLexEnvs_.count(variableName));
306     return topScopeLexEnvs_[variableName];
307 }
308 
IsFunctionOrClassDefineIns(panda::pandasm::Ins & ins)309 bool IsFunctionOrClassDefineIns(panda::pandasm::Ins &ins)
310 {
311     if (ins.opcode == panda::pandasm::Opcode::DEFINEMETHOD ||
312         ins.opcode == panda::pandasm::Opcode::DEFINEFUNC ||
313         ins.opcode == panda::pandasm::Opcode::DEFINECLASSWITHBUFFER) {
314         return true;
315     }
316     return false;
317 }
318 
IsStPatchVarIns(panda::pandasm::Ins & ins)319 bool IsStPatchVarIns(panda::pandasm::Ins &ins)
320 {
321     return ins.opcode == panda::pandasm::Opcode::WIDE_STPATCHVAR;
322 }
323 
CollectFuncDefineIns(panda::pandasm::Function * func)324 void PatchFix::CollectFuncDefineIns(panda::pandasm::Function *func)
325 {
326     for (size_t i = 0; i < func->ins.size(); ++i) {
327         if (IsFunctionOrClassDefineIns(func->ins[i])) {
328             funcDefineIns_.push_back(func->ins[i]);  // push define ins
329             funcDefineIns_.push_back(func->ins[i + 1]);  // push store ins
330         }
331     }
332 }
333 
HandleModifiedClasses(panda::pandasm::Program * prog)334 void PatchFix::HandleModifiedClasses(panda::pandasm::Program *prog)
335 {
336     for (auto &cls: classMemberFunctions_) {
337         for (auto &func: cls.second) {
338             if (!prog->function_table.at(func).metadata->IsForeign()) {
339                 modifiedClassNames_.insert(cls.first);
340                 break;
341             }
342         }
343     }
344 
345     for (auto &cls: modifiedClassNames_) {
346         auto &memberFunctions = classMemberFunctions_[cls];
347         for (auto &func: memberFunctions) {
348             if (prog->function_table.at(func).metadata->IsForeign()) {
349                 prog->function_table.at(func).metadata->RemoveAttribute(EXTERNAL_ATTRIBUTE);
350             }
351         }
352     }
353 }
354 
HandleModifiedDefinedClassFunc(panda::pandasm::Program * prog)355 void PatchFix::HandleModifiedDefinedClassFunc(panda::pandasm::Program *prog)
356 {
357     for (auto &funcInfo: funcDefinedClasses_) {
358         for (auto &definedClass: funcInfo.second) {
359             if (modifiedClassNames_.count(definedClass) &&
360                 prog->function_table.at(funcInfo.first).metadata->IsForeign()) {
361                 prog->function_table.at(funcInfo.first).metadata->RemoveAttribute(EXTERNAL_ATTRIBUTE);
362             }
363         }
364     }
365 }
366 
AddHeadAndTailInsForPatchFuncMain0(std::vector<panda::pandasm::Ins> & ins)367 void PatchFix::AddHeadAndTailInsForPatchFuncMain0(std::vector<panda::pandasm::Ins> &ins)
368 {
369     panda::pandasm::Ins returnUndefine;
370     returnUndefine.opcode = pandasm::Opcode::RETURNUNDEFINED;
371 
372     if (ins.size() == 0) {
373         ins.push_back(returnUndefine);
374         return;
375     }
376 
377     panda::pandasm::Ins newLexenv;
378     newLexenv.opcode = pandasm::Opcode::NEWLEXENV;
379     newLexenv.imms.reserve(1);
380     auto newFuncNum = long(ins.size() / 2);  // each new function has 2 ins: define and store
381     newLexenv.imms.emplace_back(newFuncNum);
382 
383     ins.insert(ins.begin(), newLexenv);
384     ins.push_back(returnUndefine);
385 }
386 
AddTailInsForPatchFuncMain1(std::vector<panda::pandasm::Ins> & ins)387 void PatchFix::AddTailInsForPatchFuncMain1(std::vector<panda::pandasm::Ins> &ins)
388 {
389     panda::pandasm::Ins returnUndefined;
390     returnUndefined.opcode = pandasm::Opcode::RETURNUNDEFINED;
391     ins.push_back(returnUndefined);
392 }
393 
CreateFunctionPatchMain0AndMain1(panda::pandasm::Function & patchFuncMain0,panda::pandasm::Function & patchFuncMain1)394 void PatchFix::CreateFunctionPatchMain0AndMain1(panda::pandasm::Function &patchFuncMain0,
395     panda::pandasm::Function &patchFuncMain1)
396 {
397     const size_t defaultParamCount = 3;
398     patchFuncMain0.params.reserve(defaultParamCount);
399     patchFuncMain1.params.reserve(defaultParamCount);
400     for (uint32_t i = 0; i < defaultParamCount; ++i) {
401         patchFuncMain0.params.emplace_back(panda::pandasm::Type("any", 0), SRC_LANG);
402         patchFuncMain1.params.emplace_back(panda::pandasm::Type("any", 0), SRC_LANG);
403     }
404 
405     std::vector<panda::pandasm::Ins> patchMain0DefineIns;
406     std::vector<panda::pandasm::Ins> patchMain1DefineIns;
407 
408     for (size_t i = 0; i < funcDefineIns_.size(); ++i) {
409         if (IsFunctionOrClassDefineIns(funcDefineIns_[i])) {
410             auto &name = funcDefineIns_[i].ids[0];
411             if (newFuncNames_.count(name) && IsStPatchVarIns(funcDefineIns_[i + 1])) {
412                 patchMain0DefineIns.push_back(funcDefineIns_[i]);
413                 patchMain0DefineIns.push_back(funcDefineIns_[i + 1]);
414                 continue;
415             }
416             if (patchFuncNames_.count(name) || modifiedClassNames_.count(name)) {
417                 patchMain1DefineIns.push_back(funcDefineIns_[i]);
418                 continue;
419             }
420         }
421     }
422 
423     AddHeadAndTailInsForPatchFuncMain0(patchMain0DefineIns);
424     AddTailInsForPatchFuncMain1(patchMain1DefineIns);
425 
426     patchFuncMain0.ins = patchMain0DefineIns;
427     patchFuncMain1.ins = patchMain1DefineIns;
428 
429     patchFuncMain0.return_type = panda::pandasm::Type("any", 0);
430     patchFuncMain1.return_type = panda::pandasm::Type("any", 0);
431 }
432 
Finalize(panda::pandasm::Program ** prog)433 void PatchFix::Finalize(panda::pandasm::Program **prog)
434 {
435     if (IsDumpSymbolTable()) {
436         return;
437     }
438 
439     HandleModifiedClasses(*prog);
440 
441     HandleModifiedDefinedClassFunc(*prog);
442 
443     if (patchError_) {
444         *prog = nullptr;
445         std::cerr << "[Patch] Found unsupported change in file, will not generate patch!" << std::endl;
446         return;
447     }
448 
449     if (IsHotReload() || IsColdFix()) {
450         return;
451     }
452 
453     panda::pandasm::Function patchFuncMain0(patchMain0_, SRC_LANG);
454     panda::pandasm::Function patchFuncMain1(patchMain1_, SRC_LANG);
455     CreateFunctionPatchMain0AndMain1(patchFuncMain0, patchFuncMain1);
456 
457     (*prog)->function_table.emplace(patchFuncMain0.name, std::move(patchFuncMain0));
458     (*prog)->function_table.emplace(patchFuncMain1.name, std::move(patchFuncMain1));
459 }
460 
CompareLexenv(const std::string & funcName,const compiler::PandaGen * pg,SymbolTable::OriginFunctionInfo & bytecodeInfo)461 bool PatchFix::CompareLexenv(const std::string &funcName, const compiler::PandaGen *pg,
462     SymbolTable::OriginFunctionInfo &bytecodeInfo)
463 {
464     auto &lexicalVarNameAndTypes = pg->TopScope()->GetLexicalVarNameAndTypes();
465     auto &lexenv = bytecodeInfo.lexenv;
466     if (funcName != funcMain0_) {
467         if (lexenv.size() != lexicalVarNameAndTypes.size()) {
468             std::cerr << "[Patch] Found lexical variable added or removed in " << funcName << ", not supported!"
469                 << std::endl;
470             patchError_ = true;
471             return false;
472         }
473         for (auto &variable: lexicalVarNameAndTypes) {
474             auto varSlot = variable.first;
475             auto lexenvIter = lexenv.find(varSlot);
476             if (lexenvIter == lexenv.end()) {
477                 std::cerr << "[Patch] Found new lexical variable added in function " << funcName << ", not supported!"
478                     << std::endl;
479                 patchError_ = true;
480                 return false;
481             }
482 
483             auto &lexInfo = lexenvIter->second;
484             if (!IsColdFix() && (std::string(variable.second.first) != lexInfo.first ||
485                                  variable.second.second != lexInfo.second)) {
486                 std::cerr << "[Patch] Found lexical variable changed in function " << funcName << ", not supported!"
487                     << std::endl;
488                 patchError_ = true;
489                 return false;
490             }
491         }
492     }
493     return true;
494 }
495 
CompareClassHash(std::vector<std::pair<std::string,std::string>> & hashList,SymbolTable::OriginFunctionInfo & bytecodeInfo)496 bool PatchFix::CompareClassHash(std::vector<std::pair<std::string, std::string>> &hashList,
497     SymbolTable::OriginFunctionInfo &bytecodeInfo)
498 {
499     auto &classInfo = bytecodeInfo.classHash;
500     for (size_t i = 0; i < hashList.size() - 1; ++i) {
501         auto &className = hashList[i].first;
502         auto classIter = classInfo.find(className);
503         if (!IsHotReload() && classIter != classInfo.end() && classIter->second != hashList[i].second) {
504             if (IsColdFix()) {
505                 modifiedClassNames_.insert(className);
506                 continue;
507             } else {
508                 ASSERT(IsHotFix());
509                 std::cerr << "[Patch] Found class " << hashList[i].first << " changed, not supported!" << std::endl;
510             }
511             patchError_ = true;
512             return false;
513         }
514     }
515     return true;
516 }
517 
CheckAndRestoreSpecialFunctionName(uint32_t globalIndexForSpecialFunc,std::string & funcInternalName,std::string recordName)518 void PatchFix::CheckAndRestoreSpecialFunctionName(uint32_t globalIndexForSpecialFunc, std::string &funcInternalName,
519     std::string recordName)
520 {
521     auto it = originRecordHashFunctionNames_->find(recordName);
522     if (it != originRecordHashFunctionNames_->end()) {
523         if (it->second.size() == 0 || globalIndexForSpecialFunc > it->second.size()) {
524             // anonymous, special or duplicate function added
525             std::cerr << "[Patch] Found new anonymous, special(containing '.' or '\\') or duplicate name function "
526                     << funcInternalName << " not supported!" << std::endl;
527             patchError_ = true;
528             return;
529         }
530         std::string originalName = it->second.at(std::to_string(globalIndexForSpecialFunc));
531         // special name function in the same position must have the same real function name as original
532         if (originalName.substr(originalName.find_last_of("#")) !=
533             funcInternalName.substr(funcInternalName.find_last_of("#"))) {
534             std::cerr << "[Patch] Found new anonymous, special(containing '.' or '\\') or duplicate name function "
535                     << funcInternalName << " not supported!" << std::endl;
536             patchError_ = true;
537             return;
538         }
539         funcInternalName = originalName;
540     }
541 }
542 
HandleFunction(const compiler::PandaGen * pg,panda::pandasm::Function * func,LiteralBuffers & literalBuffers)543 void PatchFix::HandleFunction(const compiler::PandaGen *pg, panda::pandasm::Function *func,
544     LiteralBuffers &literalBuffers)
545 {
546     std::string funcName = func->name;
547     auto originFunction = originFunctionInfo_->find(funcName);
548     if (originFunction == originFunctionInfo_->end()) {
549         newFuncNames_.insert(funcName);
550         CollectFuncDefineIns(func);
551         return;
552     }
553 
554     auto &bytecodeInfo = originFunction->second;
555     if (!CompareLexenv(funcName, pg, bytecodeInfo)) {
556         return;
557     }
558 
559     auto hashList = GenerateFunctionAndClassHash(func, literalBuffers);
560     if (!CompareClassHash(hashList, bytecodeInfo)) {
561         return;
562     }
563 
564     if (IsHotReload()) {
565         return;
566     }
567 
568     auto funcHash = hashList.back().second;
569 
570     if (funcName == funcMain0_) {
571         if (IsHotFix()) {
572             func->metadata->SetAttribute(EXTERNAL_ATTRIBUTE);
573         } else {
574             patchFuncNames_.insert(funcName);
575         }
576     } else {
577         if (funcHash == bytecodeInfo.funcHash) {
578             func->metadata->SetAttribute(EXTERNAL_ATTRIBUTE);
579         } else {
580             patchFuncNames_.insert(funcName);
581         }
582     }
583 
584     CollectFuncDefineIns(func);
585 }
586 
DumpFunctionInfo(const compiler::PandaGen * pg,panda::pandasm::Function * func,PatchFix::LiteralBuffers & literalBuffers)587 void PatchFix::DumpFunctionInfo(const compiler::PandaGen *pg, panda::pandasm::Function *func,
588     PatchFix::LiteralBuffers &literalBuffers)
589 {
590     std::stringstream ss;
591 
592     ss << pg->InternalName();
593     ss << SymbolTable::SECOND_LEVEL_SEPERATOR << pg->InternalName() << SymbolTable::SECOND_LEVEL_SEPERATOR;
594 
595     std::vector<std::pair<std::string, std::string>> hashList = GenerateFunctionAndClassHash(func, literalBuffers);
596     ss << hashList.back().second << SymbolTable::SECOND_LEVEL_SEPERATOR;
597 
598     auto internalNameStr = pg->InternalName().Mutf8();
599     if (internalNameStr.find("#") != std::string::npos) {
600         ss << (pg->Binder()->SpecialFuncNameIndexMap()).at(internalNameStr) << SymbolTable::SECOND_LEVEL_SEPERATOR;
601     } else {
602         // index 0 for all the normal name functions
603         ss << "0" << SymbolTable::SECOND_LEVEL_SEPERATOR;
604     }
605 
606     ss << SymbolTable::FIRST_LEVEL_SEPERATOR;
607     for (size_t i = 0; i < hashList.size() - 1; ++i) {
608         ss << hashList[i].first << SymbolTable::SECOND_LEVEL_SEPERATOR << hashList[i].second <<
609             SymbolTable::SECOND_LEVEL_SEPERATOR;
610     }
611     ss << SymbolTable::SECOND_LEVEL_SEPERATOR << SymbolTable::FIRST_LEVEL_SEPERATOR;
612 
613     for (auto &variable: pg->TopScope()->GetLexicalVarNameAndTypes()) {
614         ss << variable.second.first << SymbolTable::SECOND_LEVEL_SEPERATOR
615            << variable.first << SymbolTable::SECOND_LEVEL_SEPERATOR
616            << variable.second.second << SymbolTable::SECOND_LEVEL_SEPERATOR;
617     }
618     ss << SymbolTable::SECOND_LEVEL_SEPERATOR << std::endl;
619 
620     symbolTable_->WriteSymbolTable(ss.str());
621 }
622 
IsAdditionalVarInPatch(uint32_t slot)623 bool PatchFix::IsAdditionalVarInPatch(uint32_t slot)
624 {
625     return slot == UINT32_MAX;
626 }
627 
IsDumpSymbolTable() const628 bool PatchFix::IsDumpSymbolTable() const
629 {
630     return patchFixKind_ == PatchFixKind::DUMPSYMBOLTABLE;
631 }
632 
IsHotFix() const633 bool PatchFix::IsHotFix() const
634 {
635     return patchFixKind_ == PatchFixKind::HOTFIX;
636 }
637 
IsColdFix() const638 bool PatchFix::IsColdFix() const
639 {
640     return patchFixKind_ == PatchFixKind::COLDFIX;
641 }
642 
IsHotReload() const643 bool PatchFix::IsHotReload() const
644 {
645     return patchFixKind_ == PatchFixKind::HOTRELOAD;
646 }
647 
648 } // namespace panda::es2panda::util
649