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