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 (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 (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 (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 (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
GetPatchLexicalIdx(const std::string & variableName)296 uint32_t PatchFix::GetPatchLexicalIdx(const std::string &variableName)
297 {
298 ASSERT(topScopeLexEnvs_.count(variableName));
299 return topScopeLexEnvs_[variableName];
300 }
301
IsFunctionOrClassDefineIns(panda::pandasm::Ins & ins)302 bool IsFunctionOrClassDefineIns(panda::pandasm::Ins &ins)
303 {
304 if (ins.opcode == panda::pandasm::Opcode::DEFINEMETHOD ||
305 ins.opcode == panda::pandasm::Opcode::DEFINEFUNC ||
306 ins.opcode == panda::pandasm::Opcode::DEFINECLASSWITHBUFFER) {
307 return true;
308 }
309 return false;
310 }
311
IsStPatchVarIns(panda::pandasm::Ins & ins)312 bool IsStPatchVarIns(panda::pandasm::Ins &ins)
313 {
314 return ins.opcode == panda::pandasm::Opcode::WIDE_STPATCHVAR;
315 }
316
CollectFuncDefineIns(panda::pandasm::Function * func)317 void PatchFix::CollectFuncDefineIns(panda::pandasm::Function *func)
318 {
319 for (size_t i = 0; i < func->ins.size(); ++i) {
320 if (IsFunctionOrClassDefineIns(func->ins[i])) {
321 funcDefineIns_.push_back(func->ins[i]); // push define ins
322 funcDefineIns_.push_back(func->ins[i + 1]); // push store ins
323 }
324 }
325 }
326
HandleModifiedClasses(panda::pandasm::Program * prog)327 void PatchFix::HandleModifiedClasses(panda::pandasm::Program *prog)
328 {
329 for (auto &cls: classMemberFunctions_) {
330 for (auto &func: cls.second) {
331 if (!prog->function_table.at(func).metadata->IsForeign()) {
332 modifiedClassNames_.insert(cls.first);
333 break;
334 }
335 }
336 }
337
338 for (auto &cls: modifiedClassNames_) {
339 auto &memberFunctions = classMemberFunctions_[cls];
340 for (auto &func: memberFunctions) {
341 if (prog->function_table.at(func).metadata->IsForeign()) {
342 prog->function_table.at(func).metadata->RemoveAttribute(EXTERNAL_ATTRIBUTE);
343 }
344 }
345 }
346 }
347
HandleModifiedDefinedClassFunc(panda::pandasm::Program * prog)348 void PatchFix::HandleModifiedDefinedClassFunc(panda::pandasm::Program *prog)
349 {
350 for (auto &funcInfo: funcDefinedClasses_) {
351 for (auto &definedClass: funcInfo.second) {
352 if (modifiedClassNames_.count(definedClass) &&
353 prog->function_table.at(funcInfo.first).metadata->IsForeign()) {
354 prog->function_table.at(funcInfo.first).metadata->RemoveAttribute(EXTERNAL_ATTRIBUTE);
355 }
356 }
357 }
358 }
359
AddHeadAndTailInsForPatchFuncMain0(std::vector<panda::pandasm::Ins> & ins)360 void PatchFix::AddHeadAndTailInsForPatchFuncMain0(std::vector<panda::pandasm::Ins> &ins)
361 {
362 panda::pandasm::Ins returnUndefine;
363 returnUndefine.opcode = pandasm::Opcode::RETURNUNDEFINED;
364
365 if (ins.size() == 0) {
366 ins.push_back(returnUndefine);
367 return;
368 }
369
370 panda::pandasm::Ins newLexenv;
371 newLexenv.opcode = pandasm::Opcode::NEWLEXENV;
372 newLexenv.imms.reserve(1);
373 auto newFuncNum = long(ins.size() / 2); // each new function has 2 ins: define and store
374 newLexenv.imms.emplace_back(newFuncNum);
375
376 ins.insert(ins.begin(), newLexenv);
377 ins.push_back(returnUndefine);
378 }
379
AddTailInsForPatchFuncMain1(std::vector<panda::pandasm::Ins> & ins)380 void PatchFix::AddTailInsForPatchFuncMain1(std::vector<panda::pandasm::Ins> &ins)
381 {
382 panda::pandasm::Ins returnUndefined;
383 returnUndefined.opcode = pandasm::Opcode::RETURNUNDEFINED;
384 ins.push_back(returnUndefined);
385 }
386
CreateFunctionPatchMain0AndMain1(panda::pandasm::Function & patchFuncMain0,panda::pandasm::Function & patchFuncMain1)387 void PatchFix::CreateFunctionPatchMain0AndMain1(panda::pandasm::Function &patchFuncMain0,
388 panda::pandasm::Function &patchFuncMain1)
389 {
390 const size_t defaultParamCount = 3;
391 patchFuncMain0.params.reserve(defaultParamCount);
392 patchFuncMain1.params.reserve(defaultParamCount);
393 for (uint32_t i = 0; i < defaultParamCount; ++i) {
394 patchFuncMain0.params.emplace_back(panda::pandasm::Type("any", 0), SRC_LANG);
395 patchFuncMain1.params.emplace_back(panda::pandasm::Type("any", 0), SRC_LANG);
396 }
397
398 std::vector<panda::pandasm::Ins> patchMain0DefineIns;
399 std::vector<panda::pandasm::Ins> patchMain1DefineIns;
400
401 for (size_t i = 0; i < funcDefineIns_.size(); ++i) {
402 if (IsFunctionOrClassDefineIns(funcDefineIns_[i])) {
403 auto &name = funcDefineIns_[i].ids[0];
404 if (newFuncNames_.count(name) && IsStPatchVarIns(funcDefineIns_[i + 1])) {
405 patchMain0DefineIns.push_back(funcDefineIns_[i]);
406 patchMain0DefineIns.push_back(funcDefineIns_[i + 1]);
407 continue;
408 }
409 if (patchFuncNames_.count(name) || modifiedClassNames_.count(name)) {
410 patchMain1DefineIns.push_back(funcDefineIns_[i]);
411 continue;
412 }
413 }
414 }
415
416 AddHeadAndTailInsForPatchFuncMain0(patchMain0DefineIns);
417 AddTailInsForPatchFuncMain1(patchMain1DefineIns);
418
419 patchFuncMain0.ins = patchMain0DefineIns;
420 patchFuncMain1.ins = patchMain1DefineIns;
421
422 patchFuncMain0.return_type = panda::pandasm::Type("any", 0);
423 patchFuncMain1.return_type = panda::pandasm::Type("any", 0);
424 }
425
Finalize(panda::pandasm::Program ** prog)426 void PatchFix::Finalize(panda::pandasm::Program **prog)
427 {
428 if (IsDumpSymbolTable()) {
429 return;
430 }
431
432 HandleModifiedClasses(*prog);
433
434 HandleModifiedDefinedClassFunc(*prog);
435
436 if (patchError_) {
437 *prog = nullptr;
438 std::cerr << "[Patch] Found unsupported change in file, will not generate patch!" << std::endl;
439 return;
440 }
441
442 if (IsHotReload() || IsColdFix()) {
443 return;
444 }
445
446 panda::pandasm::Function patchFuncMain0(patchMain0_, SRC_LANG);
447 panda::pandasm::Function patchFuncMain1(patchMain1_, SRC_LANG);
448 CreateFunctionPatchMain0AndMain1(patchFuncMain0, patchFuncMain1);
449
450 (*prog)->function_table.emplace(patchFuncMain0.name, std::move(patchFuncMain0));
451 (*prog)->function_table.emplace(patchFuncMain1.name, std::move(patchFuncMain1));
452 }
453
CompareLexenv(const std::string & funcName,const compiler::PandaGen * pg,SymbolTable::OriginFunctionInfo & bytecodeInfo)454 bool PatchFix::CompareLexenv(const std::string &funcName, const compiler::PandaGen *pg,
455 SymbolTable::OriginFunctionInfo &bytecodeInfo)
456 {
457 auto &lexicalVarNameAndTypes = pg->TopScope()->GetLexicalVarNameAndTypes();
458 auto &lexenv = bytecodeInfo.lexenv;
459 if (funcName != funcMain0_) {
460 if (lexenv.size() != lexicalVarNameAndTypes.size()) {
461 std::cerr << "[Patch] Found lexical variable added or removed in " << funcName << ", not supported!"
462 << std::endl;
463 patchError_ = true;
464 return false;
465 }
466 for (auto &variable: lexicalVarNameAndTypes) {
467 auto varSlot = variable.first;
468 auto lexenvIter = lexenv.find(varSlot);
469 if (lexenvIter == lexenv.end()) {
470 std::cerr << "[Patch] Found new lexical variable added in function " << funcName << ", not supported!"
471 << std::endl;
472 patchError_ = true;
473 return false;
474 }
475
476 auto &lexInfo = lexenvIter->second;
477 if (!IsColdFix() && (std::string(variable.second.first) != lexInfo.first ||
478 variable.second.second != lexInfo.second)) {
479 std::cerr << "[Patch] Found lexical variable changed in function " << funcName << ", not supported!"
480 << std::endl;
481 patchError_ = true;
482 return false;
483 }
484 }
485 }
486 return true;
487 }
488
CompareClassHash(std::vector<std::pair<std::string,std::string>> & hashList,SymbolTable::OriginFunctionInfo & bytecodeInfo)489 bool PatchFix::CompareClassHash(std::vector<std::pair<std::string, std::string>> &hashList,
490 SymbolTable::OriginFunctionInfo &bytecodeInfo)
491 {
492 auto &classInfo = bytecodeInfo.classHash;
493 for (size_t i = 0; i < hashList.size() - 1; ++i) {
494 auto &className = hashList[i].first;
495 auto classIter = classInfo.find(className);
496 if (classIter != classInfo.end() && classIter->second != hashList[i].second) {
497 if (IsColdFix()) {
498 modifiedClassNames_.insert(className);
499 continue;
500 } else if (IsHotReload()) {
501 std::cerr << "[Patch] Found class " << hashList[i].first << " changed, not supported! If " <<
502 hashList[i].first << " is not changed and you are changing UI Component, please only " <<
503 "change one Component at a time and make sure the Component is placed at the bottom " <<
504 "of the file." << std::endl;
505 } else {
506 ASSERT(IsHotFix());
507 std::cerr << "[Patch] Found class " << hashList[i].first << " changed, not supported!" << std::endl;
508 }
509 patchError_ = true;
510 return false;
511 }
512 }
513 return true;
514 }
515
CheckAndRestoreSpecialFunctionName(uint32_t globalIndexForSpecialFunc,std::string & funcInternalName,std::string recordName)516 void PatchFix::CheckAndRestoreSpecialFunctionName(uint32_t globalIndexForSpecialFunc, std::string &funcInternalName,
517 std::string recordName)
518 {
519 auto it = originRecordHashFunctionNames_->find(recordName);
520 if (it != originRecordHashFunctionNames_->end()) {
521 if (it->second.size() == 0 || globalIndexForSpecialFunc > it->second.size()) {
522 // anonymous, special or duplicate function added
523 std::cerr << "[Patch] Found new anonymous, special(containing '.' or '\\') or duplicate name function "
524 << funcInternalName << " not supported!" << std::endl;
525 patchError_ = true;
526 return;
527 }
528 std::string originalName = it->second.at(std::to_string(globalIndexForSpecialFunc));
529 // special name function in the same position must have the same real function name as original
530 if (originalName.substr(originalName.find_last_of("#")) !=
531 funcInternalName.substr(funcInternalName.find_last_of("#"))) {
532 std::cerr << "[Patch] Found new anonymous, special(containing '.' or '\\') or duplicate name function "
533 << funcInternalName << " not supported!" << std::endl;
534 patchError_ = true;
535 return;
536 }
537 funcInternalName = originalName;
538 }
539 }
540
HandleFunction(const compiler::PandaGen * pg,panda::pandasm::Function * func,LiteralBuffers & literalBuffers)541 void PatchFix::HandleFunction(const compiler::PandaGen *pg, panda::pandasm::Function *func,
542 LiteralBuffers &literalBuffers)
543 {
544 std::string funcName = func->name;
545 auto originFunction = originFunctionInfo_->find(funcName);
546 if (originFunction == originFunctionInfo_->end()) {
547 newFuncNames_.insert(funcName);
548 CollectFuncDefineIns(func);
549 return;
550 }
551
552 auto &bytecodeInfo = originFunction->second;
553 if (!CompareLexenv(funcName, pg, bytecodeInfo)) {
554 return;
555 }
556
557 auto hashList = GenerateFunctionAndClassHash(func, literalBuffers);
558 if (!CompareClassHash(hashList, bytecodeInfo)) {
559 return;
560 }
561
562 if (IsHotReload()) {
563 return;
564 }
565
566 auto funcHash = hashList.back().second;
567
568 if (funcName == funcMain0_) {
569 if (IsHotFix()) {
570 func->metadata->SetAttribute(EXTERNAL_ATTRIBUTE);
571 } else {
572 patchFuncNames_.insert(funcName);
573 }
574 } else {
575 if (funcHash == bytecodeInfo.funcHash) {
576 func->metadata->SetAttribute(EXTERNAL_ATTRIBUTE);
577 } else {
578 patchFuncNames_.insert(funcName);
579 }
580 }
581
582 CollectFuncDefineIns(func);
583 }
584
DumpFunctionInfo(const compiler::PandaGen * pg,panda::pandasm::Function * func,PatchFix::LiteralBuffers & literalBuffers)585 void PatchFix::DumpFunctionInfo(const compiler::PandaGen *pg, panda::pandasm::Function *func,
586 PatchFix::LiteralBuffers &literalBuffers)
587 {
588 std::stringstream ss;
589
590 ss << pg->InternalName();
591 ss << SymbolTable::SECOND_LEVEL_SEPERATOR << pg->InternalName() << SymbolTable::SECOND_LEVEL_SEPERATOR;
592
593 std::vector<std::pair<std::string, std::string>> hashList = GenerateFunctionAndClassHash(func, literalBuffers);
594 ss << hashList.back().second << SymbolTable::SECOND_LEVEL_SEPERATOR;
595
596 auto internalNameStr = pg->InternalName().Mutf8();
597 if (internalNameStr.find("#") != std::string::npos) {
598 ss << (pg->Binder()->SpecialFuncNameIndexMap()).at(internalNameStr) << SymbolTable::SECOND_LEVEL_SEPERATOR;
599 } else {
600 // index 0 for all the normal name functions
601 ss << "0" << SymbolTable::SECOND_LEVEL_SEPERATOR;
602 }
603
604 ss << SymbolTable::FIRST_LEVEL_SEPERATOR;
605 for (size_t i = 0; i < hashList.size() - 1; ++i) {
606 ss << hashList[i].first << SymbolTable::SECOND_LEVEL_SEPERATOR << hashList[i].second <<
607 SymbolTable::SECOND_LEVEL_SEPERATOR;
608 }
609 ss << SymbolTable::SECOND_LEVEL_SEPERATOR << SymbolTable::FIRST_LEVEL_SEPERATOR;
610
611 for (auto &variable: pg->TopScope()->GetLexicalVarNameAndTypes()) {
612 ss << variable.second.first << SymbolTable::SECOND_LEVEL_SEPERATOR
613 << variable.first << SymbolTable::SECOND_LEVEL_SEPERATOR
614 << variable.second.second << SymbolTable::SECOND_LEVEL_SEPERATOR;
615 }
616 ss << SymbolTable::SECOND_LEVEL_SEPERATOR << std::endl;
617
618 symbolTable_->WriteSymbolTable(ss.str());
619 }
620
IsPatchVar(uint32_t slot)621 bool PatchFix::IsPatchVar(uint32_t slot)
622 {
623 return slot == UINT32_MAX;
624 }
625
IsDumpSymbolTable() const626 bool PatchFix::IsDumpSymbolTable() const
627 {
628 return patchFixKind_ == PatchFixKind::DUMPSYMBOLTABLE;
629 }
630
IsHotFix() const631 bool PatchFix::IsHotFix() const
632 {
633 return patchFixKind_ == PatchFixKind::HOTFIX;
634 }
635
IsColdFix() const636 bool PatchFix::IsColdFix() const
637 {
638 return patchFixKind_ == PatchFixKind::COLDFIX;
639 }
640
IsHotReload() const641 bool PatchFix::IsHotReload() const
642 {
643 return patchFixKind_ == PatchFixKind::HOTRELOAD;
644 }
645
646 } // namespace panda::es2panda::util
647