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