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