• 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 #include "ecmascript/patch/patch_loader.h"
16 
17 #include "ecmascript/global_handle_collection.h"
18 #include "ecmascript/interpreter/interpreter-inl.h"
19 #include "ecmascript/jspandafile/js_pandafile_manager.h"
20 #include "ecmascript/jspandafile/literal_data_extractor.h"
21 #include "ecmascript/mem/c_string.h"
22 #include "ecmascript/napi/include/jsnapi.h"
23 
24 namespace panda::ecmascript {
LoadPatchInternal(JSThread * thread,const JSPandaFile * baseFile,const JSPandaFile * patchFile,PatchInfo & patchInfo,const CMap<uint32_t,CString> & baseClassInfo)25 PatchErrorCode PatchLoader::LoadPatchInternal(JSThread *thread, const JSPandaFile *baseFile,
26                                               const JSPandaFile *patchFile, PatchInfo &patchInfo,
27                                               const CMap<uint32_t, CString> &baseClassInfo)
28 {
29     DISALLOW_GARBAGE_COLLECTION;
30     EcmaVM *vm = thread->GetEcmaVM();
31 
32     // hot reload and hot patch only support merge-abc file.
33     if (baseFile->IsBundlePack() || patchFile->IsBundlePack()) {
34         LOG_ECMA(ERROR) << "base or patch is not merge abc!";
35         return PatchErrorCode::PACKAGE_NOT_ESMODULE;
36     }
37 
38     // Generate patchInfo for hot reload, hot patch and cold patch.
39     patchInfo = PatchLoader::GeneratePatchInfo(patchFile);
40 
41     if (!thread->GetCurrentEcmaContext()->HasCachedConstpool(baseFile)) {
42         LOG_ECMA(INFO) << "cold patch!";
43         return PatchErrorCode::SUCCESS;
44     }
45 
46     [[maybe_unused]] EcmaHandleScope handleScope(thread);
47 
48     // store base constpool in global object for avoid gc.
49     GlobalHandleCollection gloalHandleCollection(thread);
50     for (uint32_t idx = 0; idx < baseFile->GetConstpoolNum(); idx++) {
51         JSTaggedValue constpool = thread->GetCurrentEcmaContext()->FindConstpool(baseFile, idx);
52         if (!constpool.IsHole()) {
53             JSHandle<JSTaggedValue> constpoolHandle =
54                 gloalHandleCollection.NewHandle<JSTaggedValue>(constpool.GetRawData());
55             patchInfo.baseConstpools.emplace_back(constpoolHandle);
56         }
57     }
58 
59     // create empty patch constpool for replace method constpool.
60     thread->GetCurrentEcmaContext()->CreateAllConstpool(patchFile);
61     FindAndReplaceSameMethod(thread, baseFile, patchFile, patchInfo, baseClassInfo);
62 
63     // cached patch modules can only be clear before load patch.
64     thread->GetCurrentEcmaContext()->ClearPatchModules();
65     // execute patch func_main_0 for hot reload, and patch_main_0 for hot patch.
66     ExecuteFuncOrPatchMain(thread, patchFile, patchInfo);
67     ReplaceModuleOfMethod(thread, baseFile, patchInfo);
68 
69     vm->GetJsDebuggerManager()->GetHotReloadManager()->NotifyPatchLoaded(baseFile, patchFile);
70     return PatchErrorCode::SUCCESS;
71 }
72 
ExecuteFuncOrPatchMain(JSThread * thread,const JSPandaFile * jsPandaFile,const PatchInfo & patchInfo,bool loadPatch)73 void PatchLoader::ExecuteFuncOrPatchMain(
74     JSThread *thread, const JSPandaFile *jsPandaFile, const PatchInfo &patchInfo, bool loadPatch)
75 {
76     LOG_ECMA(DEBUG) << "execute main begin";
77     EcmaContext *context = thread->GetCurrentEcmaContext();
78     context->SetStageOfHotReload(StageOfHotReload::BEGIN_EXECUTE_PATCHMAIN);
79 
80     const auto &replacedRecordNames = patchInfo.replacedRecordNames;
81 
82     // Resolve all patch module records.
83     CMap<CString, JSHandle<JSTaggedValue>> moduleRecords {};
84     for (const auto &recordName : replacedRecordNames) {
85         ModuleManager *moduleManager = context->GetModuleManager();
86         JSHandle<JSTaggedValue> moduleRecord = moduleManager->
87             HostResolveImportedModuleWithMergeForHotReload(jsPandaFile->GetJSPandaFileDesc(), recordName, false);
88         moduleRecords.emplace(recordName, moduleRecord);
89     }
90 
91     for (const auto &recordName : replacedRecordNames) {
92         LOG_ECMA(DEBUG) << "func main record name " << recordName;
93         JSHandle<Program> program =
94             JSPandaFileManager::GetInstance()->GenerateProgram(thread->GetEcmaVM(), jsPandaFile, recordName);
95         if (program.IsEmpty()) {
96             LOG_ECMA(ERROR) << "program is empty, invoke entrypoint failed";
97             continue;
98         }
99 
100         JSHandle<JSTaggedValue> moduleRecord = moduleRecords[recordName];
101         SourceTextModule::Instantiate(thread, moduleRecord, false);
102         JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
103         SourceTextModule::Evaluate(thread, module);
104     }
105 
106     if (loadPatch) {
107         context->SetStageOfHotReload(StageOfHotReload::LOAD_END_EXECUTE_PATCHMAIN);
108     } else {
109         context->SetStageOfHotReload(StageOfHotReload::UNLOAD_END_EXECUTE_PATCHMAIN);
110     }
111     LOG_ECMA(DEBUG) << "execute main end";
112 }
113 
ReplaceModuleOfMethod(JSThread * thread,const JSPandaFile * baseFile,PatchInfo & patchInfo)114 void PatchLoader::ReplaceModuleOfMethod(JSThread *thread, const JSPandaFile *baseFile, PatchInfo &patchInfo)
115 {
116     EcmaContext *context = thread->GetCurrentEcmaContext();
117     auto baseConstpoolValues = context->FindConstpools(baseFile);
118     if (!baseConstpoolValues.has_value()) {
119         LOG_ECMA(ERROR) << "replace module :base constpool is empty";
120         return;
121     }
122 
123     const auto &baseMethodInfo = patchInfo.baseMethodInfo;
124     for (const auto &item : baseMethodInfo) {
125         const auto &methodIndex = item.first;
126         ConstantPool *baseConstpool = ConstantPool::Cast(
127             (baseConstpoolValues.value().get()[methodIndex.constpoolNum]).GetTaggedObject());
128 
129         Method *patchMethod = GetPatchMethod(thread, methodIndex, baseConstpool);
130 
131         JSHandle<JSTaggedValue> moduleRecord = context->FindPatchModule(patchMethod->GetRecordNameStr());
132         patchMethod->SetModule(thread, moduleRecord.GetTaggedValue());
133         LOG_ECMA(DEBUG) << "Replace base method module: "
134                        << patchMethod->GetRecordNameStr()
135                        << ":" << patchMethod->GetMethodName();
136     }
137 }
138 
UnloadPatchInternal(JSThread * thread,const CString & patchFileName,const CString & baseFileName,PatchInfo & patchInfo)139 PatchErrorCode PatchLoader::UnloadPatchInternal(JSThread *thread, const CString &patchFileName,
140                                                 const CString &baseFileName, PatchInfo &patchInfo)
141 {
142     std::shared_ptr<JSPandaFile> baseFile = JSPandaFileManager::GetInstance()->FindJSPandaFile(baseFileName);
143     if (baseFile == nullptr) {
144         LOG_ECMA(ERROR) << "find base jsPandafile failed";
145         return PatchErrorCode::FILE_NOT_EXECUTED;
146     }
147 
148     std::shared_ptr<JSPandaFile> patchFile = JSPandaFileManager::GetInstance()->FindJSPandaFile(patchFileName);
149     if (patchFile == nullptr) {
150         LOG_ECMA(ERROR) << "find patch jsPandafile failed";
151         return PatchErrorCode::FILE_NOT_FOUND;
152     }
153 
154     const auto &baseMethodInfo = patchInfo.baseMethodInfo;
155     if (baseMethodInfo.empty()) {
156         LOG_ECMA(INFO) << "no method need to unload";
157         return PatchErrorCode::SUCCESS;
158     }
159 
160     EcmaVM *vm = thread->GetEcmaVM();
161     EcmaContext *context = thread->GetCurrentEcmaContext();
162     auto baseConstpoolValues = context->FindConstpools(baseFile.get());
163     if (!baseConstpoolValues.has_value()) {
164         LOG_ECMA(ERROR) << "base constpool is empty";
165         return PatchErrorCode::INTERNAL_ERROR;
166     }
167 
168     for (const auto &item : baseMethodInfo) {
169         const auto &methodIndex = item.first;
170         ConstantPool *baseConstpool = ConstantPool::Cast(
171             (baseConstpoolValues.value().get()[methodIndex.constpoolNum]).GetTaggedObject());
172 
173         Method *patchMethod = GetPatchMethod(thread, methodIndex, baseConstpool);
174 
175         MethodLiteral *baseMethodLiteral = item.second;
176         JSTaggedValue baseConstpoolValue = context->FindConstpool(
177             baseFile.get(), baseMethodLiteral->GetMethodId());
178         ReplaceMethod(thread, patchMethod, baseMethodLiteral, baseConstpoolValue);
179         LOG_ECMA(DEBUG) << "Replace base method: "
180                        << patchMethod->GetRecordNameStr()
181                        << ":" << patchMethod->GetMethodName();
182     }
183 
184     context->ClearPatchModules();
185     // execute base func_main_0 for recover global object.
186     ExecuteFuncOrPatchMain(thread, baseFile.get(), patchInfo, false);
187     ReplaceModuleOfMethod(thread, baseFile.get(), patchInfo);
188 
189     vm->GetJsDebuggerManager()->GetHotReloadManager()->NotifyPatchUnloaded(patchFile.get());
190 
191     // release base constpool.
192     CVector<JSHandle<JSTaggedValue>> &baseConstpools = patchInfo.baseConstpools;
193     GlobalHandleCollection gloalHandleCollection(thread);
194     for (auto &item : baseConstpools) {
195         gloalHandleCollection.Dispose(item);
196     }
197 
198     ClearPatchInfo(thread, patchFileName);
199     return PatchErrorCode::SUCCESS;
200 }
201 
GetPatchMethod(JSThread * thread,const BaseMethodIndex & methodIndex,const ConstantPool * baseConstpool)202 Method *PatchLoader::GetPatchMethod(JSThread *thread,
203     const BaseMethodIndex &methodIndex, const ConstantPool *baseConstpool)
204 {
205     uint32_t constpoolIndex = methodIndex.constpoolIndex;
206     uint32_t literalIndex = methodIndex.literalIndex;
207     Method *patchMethod = nullptr;
208     if (literalIndex == UINT32_MAX) {
209         JSTaggedValue value = baseConstpool->GetObjectFromCache(constpoolIndex);
210         ASSERT(value.IsMethod());
211         patchMethod = Method::Cast(value.GetTaggedObject());
212     } else {
213         ClassLiteral *classLiteral = ClassLiteral::Cast(baseConstpool->GetObjectFromCache(constpoolIndex));
214         TaggedArray *literalArray = TaggedArray::Cast(classLiteral->GetArray());
215         JSTaggedValue value = literalArray->Get(thread, literalIndex);
216         ASSERT(value.IsJSFunctionBase());
217         JSFunctionBase *func = JSFunctionBase::Cast(value.GetTaggedObject());
218         patchMethod = Method::Cast(func->GetMethod().GetTaggedObject());
219     }
220     return patchMethod;
221 }
222 
ClearPatchInfo(JSThread * thread,const CString & patchFileName)223 void PatchLoader::ClearPatchInfo(JSThread *thread, const CString &patchFileName)
224 {
225     EcmaVM *vm = thread->GetEcmaVM();
226 
227     vm->GetGlobalEnv()->SetGlobalPatch(thread, vm->GetFactory()->EmptyArray());
228 
229     // For release patch constpool and JSPandaFile.
230     vm->CollectGarbage(TriggerGCType::FULL_GC);
231 
232     std::shared_ptr<JSPandaFile> patchFile = JSPandaFileManager::GetInstance()->FindJSPandaFile(patchFileName);
233     if (patchFile != nullptr) {
234         LOG_ECMA(INFO) << "patch jsPandaFile is not nullptr";
235     }
236 }
237 
ReplaceMethod(JSThread * thread,Method * destMethod,MethodLiteral * srcMethodLiteral,JSTaggedValue srcConstpool)238 void PatchLoader::ReplaceMethod(JSThread *thread,
239                                 Method *destMethod,
240                                 MethodLiteral *srcMethodLiteral,
241                                 JSTaggedValue srcConstpool)
242 {
243     // Update destmethod exclude ExtraLiteralInfo(FunctionKind). Method FunctionKind will be set after
244     // building class inheritance relationship or defining gettersetter by value.
245     //
246     // HotReload of class inheritance will be affected.
247     destMethod->SetCallField(srcMethodLiteral->GetCallField());
248     destMethod->SetLiteralInfo(srcMethodLiteral->GetLiteralInfo());
249     destMethod->SetCodeEntryOrLiteral(reinterpret_cast<uintptr_t>(srcMethodLiteral));
250     destMethod->SetNativePointerOrBytecodeArray(const_cast<void *>(srcMethodLiteral->GetNativePointer()));
251     destMethod->SetConstantPool(thread, srcConstpool);
252     destMethod->SetProfileTypeInfo(thread, JSTaggedValue::Undefined());
253     destMethod->SetAotCodeBit(false);
254 }
255 
FindAndReplaceSameMethod(JSThread * thread,const JSPandaFile * baseFile,const JSPandaFile * patchFile,PatchInfo & patchInfo,const CMap<uint32_t,CString> & baseClassInfo)256 void PatchLoader::FindAndReplaceSameMethod(JSThread *thread, const JSPandaFile *baseFile,
257                                            const JSPandaFile *patchFile, PatchInfo &patchInfo,
258                                            const CMap<uint32_t, CString> &baseClassInfo)
259 {
260     auto context = thread->GetCurrentEcmaContext();
261     const CMap<int32_t, JSTaggedValue> &baseConstpoolValues = context->FindConstpools(baseFile).value();
262     for (const auto &item : baseConstpoolValues) {
263         if (item.second.IsHole()) {
264             continue;
265         }
266 
267         ConstantPool *baseConstpool = ConstantPool::Cast(item.second.GetTaggedObject());
268         uint32_t constpoolNum = item.first;
269         uint32_t baseConstpoolSize = baseConstpool->GetCacheLength();
270         for (uint32_t constpoolIndex = 0; constpoolIndex < baseConstpoolSize; constpoolIndex++) {
271             JSTaggedValue constpoolValue = baseConstpool->GetObjectFromCache(constpoolIndex);
272             if (!constpoolValue.IsMethod() && !constpoolValue.IsClassLiteral()) {
273                 continue;
274             }
275 
276             // For normal function and class constructor.
277             if (constpoolValue.IsMethod()) {
278                 Method *baseMethod = Method::Cast(constpoolValue.GetTaggedObject());
279                 EntityId baseMethodId = baseMethod->GetMethodId();
280                 MethodLiteral *patchMethodLiteral =
281                     FindSameMethod(patchInfo, baseFile, baseMethodId, baseClassInfo);
282                 if (patchMethodLiteral == nullptr) {
283                     continue;
284                 }
285 
286                 JSTaggedValue patchConstpoolValue = context->FindConstpool(patchFile,
287                     patchMethodLiteral->GetMethodId());
288                 ReplaceMethod(thread, baseMethod, patchMethodLiteral, patchConstpoolValue);
289 
290                 BaseMethodIndex indexs = {constpoolNum, constpoolIndex};
291                 SaveBaseMethodInfo(patchInfo, baseFile, baseMethodId, indexs);
292             } else if (constpoolValue.IsClassLiteral()) {
293                 // For class literal.
294                 ClassLiteral *classLiteral = ClassLiteral::Cast(constpoolValue);
295                 TaggedArray *literalArray = TaggedArray::Cast(classLiteral->GetArray());
296                 uint32_t literalLength = literalArray->GetLength();
297                 for (uint32_t literalIndex = 0; literalIndex < literalLength; literalIndex++) {
298                     JSTaggedValue literalItem = literalArray->Get(thread, literalIndex);
299                     if (!literalItem.IsJSFunctionBase()) {
300                         continue;
301                     }
302 
303                     // Every record is the same in current class literal.
304                     JSFunctionBase *func = JSFunctionBase::Cast(literalItem.GetTaggedObject());
305                     Method *baseMethod = Method::Cast(func->GetMethod().GetTaggedObject());
306                     EntityId baseMethodId = baseMethod->GetMethodId();
307                     MethodLiteral *patchMethodLiteral =
308                         FindSameMethod(patchInfo, baseFile, baseMethodId, baseClassInfo);
309                     if (patchMethodLiteral == nullptr) {
310                         continue;
311                     }
312 
313                     JSTaggedValue patchConstpoolValue = context->FindConstpool(patchFile,
314                         patchMethodLiteral->GetMethodId());
315                     ReplaceMethod(thread, baseMethod, patchMethodLiteral, patchConstpoolValue);
316 
317                     BaseMethodIndex indexs = {constpoolNum, constpoolIndex, literalIndex};
318                     SaveBaseMethodInfo(patchInfo, baseFile, baseMethodId, indexs);
319                 }
320             }
321         }
322     }
323 }
324 
FindSameMethod(PatchInfo & patchInfo,const JSPandaFile * baseFile,EntityId baseMethodId,const CMap<uint32_t,CString> & baseClassInfo)325 MethodLiteral* PatchLoader::FindSameMethod(PatchInfo &patchInfo, const JSPandaFile *baseFile,
326     EntityId baseMethodId, const CMap<uint32_t, CString> &baseClassInfo)
327 {
328     const CUnorderedMap<PatchMethodIndex, MethodLiteral*, PatchMethodIndex::Hash> &patchMethodLiterals =
329         patchInfo.patchMethodLiterals;
330     CString baseRecordName = MethodLiteral::GetRecordName(baseFile, baseMethodId);
331     CString baseClassName = "default";
332     auto iter = baseClassInfo.find(baseMethodId.GetOffset());
333     if (iter != baseClassInfo.end()) {
334         baseClassName = iter->second;
335     }
336     CString baseMethodName = GetRealName(baseFile, baseMethodId, baseClassName);
337     PatchMethodIndex patchMethodIndex = {baseRecordName, baseClassName, baseMethodName};
338     auto methodIter = patchMethodLiterals.find(patchMethodIndex);
339     if (methodIter == patchMethodLiterals.end()) {
340         return nullptr;
341     }
342 
343     // Reserved for HotPatch.
344     patchInfo.replacedRecordNames.emplace(baseRecordName);
345     return methodIter->second;
346 }
347 
SaveBaseMethodInfo(PatchInfo & patchInfo,const JSPandaFile * baseFile,EntityId baseMethodId,const BaseMethodIndex & indexs)348 void PatchLoader::SaveBaseMethodInfo(PatchInfo &patchInfo, const JSPandaFile *baseFile,
349                                      EntityId baseMethodId, const BaseMethodIndex &indexs)
350 {
351     CUnorderedMap<BaseMethodIndex, MethodLiteral *, BaseMethodIndex::Hash> &baseMethodInfo = patchInfo.baseMethodInfo;
352     MethodLiteral *baseMethodLiteral = baseFile->FindMethodLiteral(baseMethodId.GetOffset());
353     ASSERT(baseMethodLiteral != nullptr);
354     baseMethodInfo.emplace(indexs, baseMethodLiteral);
355 }
356 
GeneratePatchInfo(const JSPandaFile * patchFile)357 PatchInfo PatchLoader::GeneratePatchInfo(const JSPandaFile *patchFile)
358 {
359     CMap<uint32_t, CString> patchClassInfo = CollectClassInfo(patchFile);
360 
361     const auto &map = patchFile->GetMethodLiteralMap();
362     CUnorderedMap<PatchMethodIndex, MethodLiteral*, PatchMethodIndex::Hash> patchMethodLiterals;
363     PatchInfo patchInfo;
364     for (const auto &item : map) {
365         MethodLiteral *methodLiteral = item.second;
366         EntityId methodId = EntityId(item.first);
367         CString className = "default"; // for normal method and constructor.
368         auto iter = patchClassInfo.find(methodId.GetOffset());
369         if (iter!= patchClassInfo.end()) {
370             className = iter->second;
371         }
372         CString methodName = GetRealName(patchFile, methodId, className);
373         if (methodName == JSPandaFile::PATCH_FUNCTION_NAME_0 ||
374             methodName == JSPandaFile::PATCH_FUNCTION_NAME_1) {
375             continue;
376         }
377 
378         // if patchFile only include varibales, add recordName specially.
379         CString recordName = MethodLiteral::GetRecordName(patchFile, methodId);
380         if (methodName == JSPandaFile::ENTRY_FUNCTION_NAME) {
381             patchInfo.replacedRecordNames.emplace(recordName);
382         }
383 
384         PatchMethodIndex patchMethodIndex = {recordName, className, methodName};
385         if (patchMethodLiterals.find(patchMethodIndex) == patchMethodLiterals.end()) {
386             patchMethodLiterals.emplace(patchMethodIndex, methodLiteral);
387         }
388     }
389 
390     patchInfo.patchFileName = patchFile->GetJSPandaFileDesc();
391     patchInfo.patchMethodLiterals = std::move(patchMethodLiterals);
392     return patchInfo;
393 }
394 
CollectClassInfo(const JSPandaFile * jsPandaFile)395 CMap<uint32_t, CString> PatchLoader::CollectClassInfo(const JSPandaFile *jsPandaFile)
396 {
397     CMap<uint32_t, CString> classInfo {};
398     auto &pandaFile = *jsPandaFile->GetPandaFile();
399     auto classes = jsPandaFile->GetClasses();
400     const auto &map = jsPandaFile->GetMethodLiteralMap();
401     for (size_t i = 0; i < classes.Size(); i++) {
402         EntityId classId(classes[i]);
403         if (!classId.IsValid() || jsPandaFile->IsExternal(classId)) {
404             continue;
405         }
406 
407         panda_file::ClassDataAccessor cda(pandaFile, classId);
408         cda.EnumerateMethods([&pandaFile, &map, &classInfo, jsPandaFile](panda_file::MethodDataAccessor &mda) {
409             EntityId methodId = mda.GetMethodId();
410             auto iter = map.find(methodId.GetOffset());
411             MethodLiteral *methodLiteral = nullptr;
412             if (iter != map.end()) {
413                 methodLiteral = iter->second;
414             }
415 
416             auto codeId = mda.GetCodeId();
417             ASSERT(codeId.has_value());
418             panda_file::CodeDataAccessor codeDataAccessor(pandaFile, codeId.value());
419             uint32_t codeSize = codeDataAccessor.GetCodeSize();
420             const uint8_t *insns = codeDataAccessor.GetInstructions();
421 
422             auto bcIns = BytecodeInst(insns);
423             auto bcInsLast = bcIns.JumpTo(codeSize);
424             while (bcIns.GetAddress() != bcInsLast.GetAddress()) {
425                 BytecodeInstruction::Opcode opcode = static_cast<BytecodeInstruction::Opcode>(bcIns.GetOpcode());
426                 if (opcode == BytecodeInstruction::Opcode::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8 ||
427                     opcode == BytecodeInstruction::Opcode::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8) {
428                     auto entityId = jsPandaFile->ResolveMethodIndex(methodLiteral->GetMethodId(),
429                         (bcIns.GetId <BytecodeInstruction::Format::IMM8_ID16_ID16_IMM16_V8, 0>()).AsRawValue());
430                     CString className = "";
431                     className = GetRealName(jsPandaFile, entityId, className);
432                     CString recordName = MethodLiteral::GetRecordName(jsPandaFile, methodId);
433 
434                     auto literalId = jsPandaFile->ResolveMethodIndex(methodLiteral->GetMethodId(),
435                         (bcIns.GetId <BytecodeInstruction::Format::IMM8_ID16_ID16_IMM16_V8, 1>()).AsRawValue());
436                     LiteralDataAccessor lda = jsPandaFile->GetLiteralDataAccessor();
437                     lda.EnumerateLiteralVals(literalId, [&classInfo, className]
438                         (const LiteralValue &value, const LiteralTag &tag) {
439                             switch (tag) {
440                                 case LiteralTag::METHOD:
441                                 case LiteralTag::GENERATORMETHOD: {
442                                     uint32_t methodOffset = std::get<uint32_t>(value);
443                                     classInfo.emplace(methodOffset, std::move(className));
444                                     break;
445                                 }
446                                 default: {
447                                     break;
448                                 }
449                             }
450                     });
451                 }
452                 auto nextInst = bcIns.GetNext();
453                 bcIns = nextInst;
454             }
455         });
456     }
457     return classInfo;
458 }
459 
GetRealName(const JSPandaFile * jsPandaFile,EntityId entityId,CString & className)460 CString PatchLoader::GetRealName(const JSPandaFile *jsPandaFile, EntityId entityId, CString &className)
461 {
462     std::string methodName(MethodLiteral::GetMethodName(jsPandaFile, entityId));
463     size_t poiIndex = methodName.find_last_of('#');
464     if (poiIndex != std::string::npos && poiIndex < methodName.size() - 1 && className != "default") {
465         methodName = methodName.substr(poiIndex + 1);
466     }
467     return ConvertToString(methodName);
468 }
469 }  // namespace panda::ecmascript