• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "ecmascript/jspandafile/js_pandafile_manager.h"
17 
18 #include "ecmascript/checkpoint/thread_state_transition.h"
19 #include "ecmascript/jspandafile/abc_buffer_cache.h"
20 #include "ecmascript/jspandafile/js_pandafile_executor.h"
21 #include "ecmascript/module/module_path_helper.h"
22 #include "ecmascript/module/module_message_helper.h"
23 #include "ecmascript/module/module_tools.h"
24 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
25 #include "ecmascript/platform/pandafile.h"
26 
27 namespace panda::ecmascript {
28 using PGOProfilerManager = pgo::PGOProfilerManager;
29 static const size_t MALLOC_SIZE_LIMIT = 2147483648; // Max internal memory used by the VM declared in options
30 
GetInstance()31 JSPandaFileManager *JSPandaFileManager::GetInstance()
32 {
33     static JSPandaFileManager *jsFileManager = new JSPandaFileManager();
34     return jsFileManager;
35 }
36 
~JSPandaFileManager()37 JSPandaFileManager::~JSPandaFileManager()
38 {
39     LockHolder lock(jsPandaFileLock_);
40     extractors_.clear();
41     oldJSPandaFiles_.clear();
42     loadedJSPandaFiles_.clear();
43 }
44 
45 /*
46  * Typically return nullptr for JSPandafile load fail. Throw cppcrash if load hsp failed.
47  * Specifically, return jscrash if napi load hsp failed.
48 */
LoadJSPandaFile(JSThread * thread,const CString & filename,std::string_view entryPoint,bool needUpdate,const ExecuteTypes & executeType)49 std::shared_ptr<JSPandaFile> JSPandaFileManager::LoadJSPandaFile(JSThread *thread, const CString &filename,
50     std::string_view entryPoint, bool needUpdate, const ExecuteTypes &executeType)
51 {
52     {
53         LockHolder lock(jsPandaFileLock_);
54         std::shared_ptr<JSPandaFile> jsPandaFile;
55         if (needUpdate) {
56             auto pf = panda_file::OpenPandaFileOrZip(filename, panda_file::File::READ_WRITE);
57             if (pf == nullptr) {
58                 LOG_ECMA(ERROR) << "open file " << filename << " error";
59                 return nullptr;
60             }
61             jsPandaFile = FindJSPandaFileWithChecksum(filename, pf->GetHeader()->checksum);
62         } else {
63             jsPandaFile = FindJSPandaFileUnlocked(filename);
64             if (jsPandaFile == nullptr) {
65                 jsPandaFile = GenerateJSPandafileFromBufferCache(thread, filename, entryPoint);
66             }
67         }
68         if (jsPandaFile != nullptr) {
69             return jsPandaFile;
70         }
71     }
72 
73     EcmaVM *vm = thread->GetEcmaVM();
74     ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
75     std::unique_ptr<const panda_file::File> pf;
76     if (!vm->IsBundlePack() && moduleManager->GetExecuteMode() == ModuleExecuteMode::ExecuteBufferMode &&
77         !vm->IsRestrictedWorkerThread()) {
78         ResolveBufferCallback resolveBufferCallback = vm->GetResolveBufferCallback();
79         if (resolveBufferCallback == nullptr) {
80             LoadJSPandaFileFailLog("[ArkRuntime Log] Importing shared package is not supported in the Previewer.");
81             LOG_FULL(FATAL) << "resolveBufferCallback is nullptr";
82             return nullptr;
83         }
84         std::string hspPath = ModulePathHelper::ParseHapPath(filename);
85         if (hspPath.empty()) {
86             LOG_FULL(ERROR) << ModuleMessageHelper::VmModuleInfoMessage(thread);
87             if (!thread->IsMainThread()) {
88                 CString msg = "Invalid input hsp path: " + filename;
89                 THROW_TYPE_ERROR_AND_RETURN(thread, msg.c_str(), nullptr);
90             }
91             LOG_FULL(FATAL) << "Invalid input hsp path: " << filename;
92             return nullptr;
93         }
94         uint8_t *data = nullptr;
95         size_t dataSize = 0;
96         std::string errorMsg;
97         bool getBuffer = resolveBufferCallback(hspPath, &data, &dataSize, errorMsg);
98         if (!getBuffer) {
99             LoadJSPandaFileFailLog("[ArkRuntime Log] Importing shared package in the Previewer.");
100             CString msg = "resolveBufferCallback get hsp buffer failed, hsp path:" + filename +
101                 ", errorMsg:" + errorMsg.c_str();
102             if (executeType == ExecuteTypes::NAPI) {
103                 LOG_FULL(ERROR) << msg;
104                 THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), nullptr);
105             }
106             LOG_FULL(FATAL) << msg;
107             return nullptr;
108         }
109         pf = OpenPandaFileFromMemory(data, dataSize);
110     } else if (vm->IsRestrictedWorkerThread()) {
111         // ReadOnly
112         pf = panda_file::OpenPandaFileOrZip(filename);
113     } else {
114         pf = panda_file::OpenPandaFileOrZip(filename, panda_file::File::READ_WRITE);
115     }
116 
117     if (pf == nullptr) {
118         LOG_ECMA(ERROR) << "open file " << filename << " error";
119         return nullptr;
120     }
121 
122     std::shared_ptr<JSPandaFile> jsPandaFile = GenerateJSPandaFile(thread, pf.release(), filename, entryPoint);
123 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
124     if (thread->GetIsProfiling()) {
125         GetJSPtExtractorAndExtract(jsPandaFile.get());
126     }
127 #endif
128     return jsPandaFile;
129 }
130 
131 // The security interface needs to be modified accordingly.
LoadJSPandaFile(JSThread * thread,const CString & filename,std::string_view entryPoint,const void * buffer,size_t size,bool needUpdate)132 std::shared_ptr<JSPandaFile> JSPandaFileManager::LoadJSPandaFile(JSThread *thread, const CString &filename,
133     std::string_view entryPoint, const void *buffer, size_t size, bool needUpdate)
134 {
135     if (buffer == nullptr || size == 0) {
136         LOG_FULL(ERROR) << "Input buffer is empty";
137         return nullptr;
138     }
139     {
140         LockHolder lock(jsPandaFileLock_);
141         std::shared_ptr<JSPandaFile> jsPandaFile;
142         if (needUpdate) {
143             auto pf = panda_file::OpenPandaFileFromMemory(buffer, size);
144             if (pf == nullptr) {
145                 LOG_ECMA(ERROR) << "open file buffer " << filename << " error";
146                 return nullptr;
147             }
148             jsPandaFile = FindJSPandaFileWithChecksum(filename, pf->GetHeader()->checksum);
149         } else {
150             jsPandaFile = FindJSPandaFileUnlocked(filename);
151         }
152         if (jsPandaFile != nullptr) {
153             return jsPandaFile;
154         }
155     }
156     auto pf = ParseAndOpenPandaFile(buffer, size, filename);
157     if (pf == nullptr) {
158         LOG_ECMA(ERROR) << "open file " << filename << " error";
159         return nullptr;
160     }
161 
162     // JSPandaFile desc cannot be empty, if buffer with empty filename, use pf filename as a descriptor.
163     const CString &desc = filename.empty() ? pf->GetFilename().c_str() : filename;
164 
165     std::shared_ptr<JSPandaFile> jsPandaFile = GenerateJSPandaFile(thread, pf.release(), desc, entryPoint);
166 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
167     if (thread->GetIsProfiling()) {
168         GetJSPtExtractorAndExtract(jsPandaFile.get());
169     }
170 #endif
171     return jsPandaFile;
172 }
173 
LoadJSPandaFileSecure(JSThread * thread,const CString & filename,std::string_view entryPoint,uint8_t * buffer,size_t size,bool needUpdate)174 std::shared_ptr<JSPandaFile> JSPandaFileManager::LoadJSPandaFileSecure(JSThread *thread, const CString &filename,
175     std::string_view entryPoint, uint8_t *buffer, size_t size, bool needUpdate)
176 {
177     CString traceInfo = "JSPandaFileManager::LoadJSPandaFileSecure:" + filename;
178     ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, traceInfo.c_str());
179     if (buffer == nullptr || size == 0) {
180         LOG_FULL(ERROR) << "Input buffer is empty";
181         return nullptr;
182     }
183     {
184         LockHolder lock(jsPandaFileLock_);
185         std::shared_ptr<JSPandaFile> jsPandaFile;
186         if (needUpdate) {
187             auto pf = panda_file::OpenPandaFileFromSecureMemory(buffer, size);
188             if (pf == nullptr) {
189                 LOG_ECMA(ERROR) << "open file buffer " << filename << " error";
190                 return nullptr;
191             }
192             jsPandaFile = FindJSPandaFileWithChecksum(filename, pf->GetHeader()->checksum);
193         } else {
194             jsPandaFile = FindJSPandaFileUnlocked(filename);
195         }
196         if (jsPandaFile != nullptr) {
197             return jsPandaFile;
198         }
199     }
200 
201     auto pf = panda_file::OpenPandaFileFromSecureMemory(buffer, size);
202     if (pf == nullptr) {
203         LOG_ECMA(ERROR) << "open file " << filename << " error";
204         return nullptr;
205     }
206 
207     // JSPandaFile desc cannot be empty, if buffer with empty filename, use pf filename as a descriptor.
208     const CString &desc = filename.empty() ? pf->GetFilename().c_str() : filename;
209 
210     std::shared_ptr<JSPandaFile> jsPandaFile = GenerateJSPandaFile(thread, pf.release(), desc, entryPoint);
211 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
212     if (thread->GetIsProfiling()) {
213         GetJSPtExtractorAndExtract(jsPandaFile.get());
214     }
215 #endif
216     return jsPandaFile;
217 }
218 
GenerateProgram(EcmaVM * vm,const JSPandaFile * jsPandaFile,std::string_view entryPoint)219 JSHandle<Program> JSPandaFileManager::GenerateProgram(EcmaVM *vm, const JSPandaFile *jsPandaFile,
220                                                       std::string_view entryPoint)
221 {
222     ASSERT(GetJSPandaFile(jsPandaFile->GetPandaFile()) != nullptr);
223     return PandaFileTranslator::GenerateProgram(vm, jsPandaFile, entryPoint);
224 }
225 
FindJSPandaFileWithChecksum(const CString & filename,uint32_t checksum)226 std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFileWithChecksum(const CString &filename, uint32_t checksum)
227 {
228     std::shared_ptr<JSPandaFile> jsPandaFile = FindJSPandaFileUnlocked(filename);
229     if (jsPandaFile == nullptr) {
230         return nullptr;
231     }
232 
233     if (checksum == jsPandaFile->GetChecksum()) {
234         return jsPandaFile;
235     }
236 
237     LOG_FULL(INFO) << "reload " << filename << " with new checksum";
238     ObsoleteLoadedJSPandaFile(filename);
239     return nullptr;
240 }
241 
FindMergedJSPandaFile()242 std::shared_ptr<JSPandaFile> JSPandaFileManager::FindMergedJSPandaFile()
243 {
244     LockHolder lock(jsPandaFileLock_);
245     for (const auto &iter : loadedJSPandaFiles_) {
246         const std::shared_ptr<JSPandaFile> &jsPandafile = iter.second;
247         if (jsPandafile->IsFirstMergedAbc()) {
248             return jsPandafile;
249         }
250     }
251     return nullptr;
252 }
253 
FindJSPandaFileUnlocked(const CString & filename)254 std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFileUnlocked(const CString &filename)
255 {
256     if (filename.empty()) {
257         return nullptr;
258     }
259     const auto iter = loadedJSPandaFiles_.find(filename);
260     if (iter == loadedJSPandaFiles_.end()) {
261         return nullptr;
262     }
263     return iter->second;
264 }
265 
FindJSPandaFileByNormalizedName(const CString & normalizedName)266 std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFileByNormalizedName(const CString &normalizedName)
267 {
268     if (normalizedName.empty()) {
269         return nullptr;
270     }
271     std::shared_ptr<JSPandaFile> result;
272     EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool {
273         // normalize path inside and outside sandbox
274         if (file->GetNormalizedFileDesc() == normalizedName) {
275             result = file;
276             return false;
277         }
278         return true;
279     });
280     return result;
281 }
282 
FindJSPandaFileByMapBase(uintptr_t mapBase)283 std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFileByMapBase(uintptr_t mapBase)
284 {
285     std::shared_ptr<JSPandaFile> result;
286     EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool {
287         if (reinterpret_cast<uintptr_t>(file->GetHeader()) == mapBase) {
288             result = file;
289             return false;
290         }
291         return true;
292     });
293     return result;
294 }
295 
FindJSPandaFile(const CString & filename)296 std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFile(const CString &filename)
297 {
298     LockHolder lock(jsPandaFileLock_);
299     return FindJSPandaFileUnlocked(filename);
300 }
301 
GetJSPandaFile(const panda_file::File * pf)302 std::shared_ptr<JSPandaFile> JSPandaFileManager::GetJSPandaFile(const panda_file::File *pf)
303 {
304     LockHolder lock(jsPandaFileLock_);
305     for (const auto &iter : loadedJSPandaFiles_) {
306         const std::shared_ptr<JSPandaFile> &jsPandafile = iter.second;
307         if (jsPandafile->GetPandaFile() == pf) {
308             return jsPandafile;
309         }
310     }
311     return nullptr;
312 }
313 
ClearNameMap()314 void JSPandaFileManager::ClearNameMap()
315 {
316     LockHolder lock(jsPandaFileLock_);
317     for (const auto &iter : loadedJSPandaFiles_) {
318         iter.second->ClearNameMap();
319     }
320 }
321 
AddJSPandaFile(const std::shared_ptr<JSPandaFile> & jsPandaFile)322 void JSPandaFileManager::AddJSPandaFile(const std::shared_ptr<JSPandaFile> &jsPandaFile)
323 {
324     const auto &filename = jsPandaFile->GetJSPandaFileDesc();
325     LockHolder lock(jsPandaFileLock_);
326     if (loadedJSPandaFiles_.find(filename) != loadedJSPandaFiles_.end()) {
327         LOG_ECMA(FATAL) << "add failed, file already exist: " << filename;
328         UNREACHABLE();
329     }
330 
331     loadedJSPandaFiles_[filename] = std::move(jsPandaFile);
332     JSPandaFileExecutor::BindPandaFileToAot(jsPandaFile.get());
333     LOG_ECMA(DEBUG) << "add file: " << filename;
334 }
335 
RemoveJSPandaFile(const JSPandaFile * jsPandaFile)336 void JSPandaFileManager::RemoveJSPandaFile(const JSPandaFile *jsPandaFile)
337 {
338     if (jsPandaFile == nullptr) {
339         return;
340     }
341 
342     LockHolder lock(jsPandaFileLock_);
343     auto iterOld = oldJSPandaFiles_.begin();
344     while (iterOld != oldJSPandaFiles_.end()) {
345         if (iterOld->get() == jsPandaFile) {
346             extractors_.erase(jsPandaFile);
347             oldJSPandaFiles_.erase(iterOld);
348             return;
349         }
350         iterOld++;
351     }
352     const auto &filename = jsPandaFile->GetJSPandaFileDesc();
353     auto iter = loadedJSPandaFiles_.find(filename);
354     if (iter != loadedJSPandaFiles_.end()) {
355         extractors_.erase(jsPandaFile);
356         // erase shared_ptr from map, the ref count -1.
357         loadedJSPandaFiles_.erase(iter);
358     }
359 }
360 
ObsoleteLoadedJSPandaFile(const CString & filename)361 void JSPandaFileManager::ObsoleteLoadedJSPandaFile(const CString &filename)
362 {
363     auto iter = loadedJSPandaFiles_.find(filename);
364     ASSERT(iter != loadedJSPandaFiles_.end());
365     std::shared_ptr<JSPandaFile> &jsPandaFile = iter->second;
366     if (oldJSPandaFiles_.find(jsPandaFile) == oldJSPandaFiles_.end()) {
367         oldJSPandaFiles_.emplace(jsPandaFile);
368     }
369     loadedJSPandaFiles_.erase(iter);
370 }
371 
OpenJSPandaFile(const CString & filename)372 std::shared_ptr<JSPandaFile> JSPandaFileManager::OpenJSPandaFile(const CString &filename)
373 {
374     return OpenJSPandaFile(filename, filename);
375 }
376 
OpenJSPandaFile(const CString & filename,const CString & desc)377 std::shared_ptr<JSPandaFile> JSPandaFileManager::OpenJSPandaFile(const CString &filename, const CString &desc)
378 {
379     auto pf = panda_file::OpenPandaFileOrZip(filename, panda_file::File::READ_WRITE);
380     if (pf == nullptr) {
381         LOG_ECMA(ERROR) << "open file " << filename << " error";
382         return nullptr;
383     }
384 
385     return NewJSPandaFile(pf.release(), desc);
386 }
387 
OpenJSPandaFileFromBuffer(uint8_t * buffer,size_t size,const CString & filename)388 std::shared_ptr<JSPandaFile> JSPandaFileManager::OpenJSPandaFileFromBuffer(uint8_t *buffer,
389                                                                            size_t size,
390                                                                            const CString &filename)
391 {
392     auto pf = panda_file::OpenPandaFileFromMemory(buffer, size);
393     if (pf == nullptr) {
394         LOG_ECMA(ERROR) << "open file " << filename << " error";
395         return nullptr;
396     }
397 
398     return NewJSPandaFile(pf.release(), filename);
399 }
400 
NewJSPandaFile(const panda_file::File * pf,const CString & desc)401 std::shared_ptr<JSPandaFile> JSPandaFileManager::NewJSPandaFile(const panda_file::File *pf, const CString &desc)
402 {
403     std::shared_ptr<JSPandaFile> jsPandaFile = std::make_shared<JSPandaFile>(pf, desc);
404     PGOProfilerManager::GetInstance()->SamplePandaFileInfo(jsPandaFile->GetChecksum(),
405                                                            jsPandaFile->GetJSPandaFileDesc());
406     return jsPandaFile;
407 }
408 
GetJSPtExtractor(const JSPandaFile * jsPandaFile)409 DebugInfoExtractor *JSPandaFileManager::GetJSPtExtractor(const JSPandaFile *jsPandaFile)
410 {
411     LOG_ECMA_IF(jsPandaFile == nullptr, FATAL) << "GetJSPtExtractor error, js pandafile is nullptr";
412 
413     LockHolder lock(jsPandaFileLock_);
414     const auto &filename = jsPandaFile->GetJSPandaFileDesc();
415     if (loadedJSPandaFiles_.find(filename) == loadedJSPandaFiles_.end()) {
416         LOG_ECMA(FATAL) << "get extractor failed, file not exist: " << filename
417             << " file addr is " << reinterpret_cast<uintptr_t>(jsPandaFile->GetHeader());
418         UNREACHABLE();
419     }
420 
421     auto iter = extractors_.find(jsPandaFile);
422     if (iter == extractors_.end()) {
423         auto extractorPtr = std::make_unique<DebugInfoExtractor>(jsPandaFile);
424         DebugInfoExtractor *extractor = extractorPtr.get();
425         extractors_[jsPandaFile] = std::move(extractorPtr);
426         return extractor;
427     }
428 
429     return iter->second.get();
430 }
431 
GetJSPtExtractorAndExtract(const JSPandaFile * jsPandaFile)432 DebugInfoExtractor *JSPandaFileManager::GetJSPtExtractorAndExtract(const JSPandaFile *jsPandaFile)
433 {
434     LOG_ECMA_IF(jsPandaFile == nullptr, FATAL) << "GetJSPtExtractor error, js pandafile is nullptr";
435 
436     LockHolder lock(jsPandaFileLock_);
437     const auto &filename = jsPandaFile->GetJSPandaFileDesc();
438     if (loadedJSPandaFiles_.find(filename) == loadedJSPandaFiles_.end()) {
439         LOG_ECMA(FATAL) << "get extractor failed, file not exist: " << filename;
440         UNREACHABLE();
441     }
442 
443     auto iter = extractors_.find(jsPandaFile);
444     if (iter == extractors_.end()) {
445         auto extractorPtr = std::make_unique<DebugInfoExtractor>(jsPandaFile);
446         DebugInfoExtractor *extractor = extractorPtr.get();
447         extractor->Extract();
448         extractors_[jsPandaFile] = std::move(extractorPtr);
449         return extractor;
450     }
451 
452     return iter->second.get();
453 }
454 
CpuProfilerGetJSPtExtractor(const JSPandaFile * jsPandaFile)455 DebugInfoExtractor *JSPandaFileManager::CpuProfilerGetJSPtExtractor(const JSPandaFile *jsPandaFile)
456 {
457     LOG_ECMA_IF(jsPandaFile == nullptr, FATAL) << "GetJSPtExtractor error, js pandafile is nullptr";
458 
459     LockHolder lock(jsPandaFileLock_);
460     const auto &filename = jsPandaFile->GetJSPandaFileDesc();
461     if (loadedJSPandaFiles_.find(filename) == loadedJSPandaFiles_.end()) {
462         LOG_ECMA(FATAL) << "get extractor failed, file not exist: " << filename;
463         UNREACHABLE();
464     }
465 
466     DebugInfoExtractor *extractor = nullptr;
467     auto iter = extractors_.find(jsPandaFile);
468     if (iter == extractors_.end()) {
469         auto extractorPtr = std::make_unique<DebugInfoExtractor>(jsPandaFile);
470         extractor = extractorPtr.get();
471         extractors_[jsPandaFile] = std::move(extractorPtr);
472     } else {
473         extractor = iter->second.get();
474     }
475 
476     extractor->Extract();
477     return extractor;
478 }
479 
GetModuleNameFromDesc(const std::string & desc)480 std::string GetModuleNameFromDesc(const std::string &desc)
481 {
482     /*
483     handle desc like:
484     case1: /data/storage/el1/bundle/entry/ets/modules.abc -> entry/ets/modules.abc
485     case2: /data/storage/el1/bundle/entry/ets/widgets.abc -> entry/ets/widgets.abc
486     case3: /data/app/el1/bundle/public/com.xx.xx/entry/ets/modules.abc -> entry/ets/modules.abc
487     case4: /data/app/el1/bundle/public/com.xx.xx/entry/ets/widgets.abc -> entry/ets/widgets.abc
488     */
489     auto lastSlash = desc.rfind("/");
490     if (lastSlash == std::string::npos) {
491         LOG_ECMA(DEBUG) << "GetModuleNameFromDesc can't find fisrt /: " << desc;
492         return "";
493     }
494     ASSERT(lastSlash > 0);
495     auto secondLastSlash = desc.rfind("/", lastSlash - 1);
496     if (secondLastSlash == std::string::npos) {
497         LOG_ECMA(DEBUG) << "GetModuleNameFromDesc can't find second /: " << desc;
498         return "";
499     }
500     ASSERT(secondLastSlash > 0);
501     auto thirdLastSlash = desc.rfind("/", secondLastSlash - 1);
502     if (thirdLastSlash == std::string::npos) {
503         LOG_ECMA(DEBUG) << "GetModuleNameFromDesc can't find third /: " << desc;
504         return "";
505     }
506     // get moduleName from thirdLastSlash to secondLastSlash
507     return desc.substr(thirdLastSlash + 1, secondLastSlash - thirdLastSlash - 1);
508 }
509 
GenerateJSPandaFile(JSThread * thread,const panda_file::File * pf,const CString & desc,std::string_view entryPoint)510 std::shared_ptr<JSPandaFile> JSPandaFileManager::GenerateJSPandaFile(JSThread *thread, const panda_file::File *pf,
511                                                                      const CString &desc, std::string_view entryPoint)
512 {
513     ThreadNativeScope nativeScope(thread);
514     ASSERT(GetJSPandaFile(pf) == nullptr);
515     std::shared_ptr<JSPandaFile> newJsPandaFile = NewJSPandaFile(pf, desc);
516     EcmaVM *vm = thread->GetEcmaVM();
517 
518     std::string moduleName = GetModuleNameFromDesc(desc.c_str());
519     std::string hapPath;
520     SearchHapPathCallBack callback = vm->GetSearchHapPathCallBack();
521     if (callback) {
522         callback(moduleName, hapPath);
523         LOG_ECMA(DEBUG) << "SearchHapPathCallBack moduleName: " << moduleName
524                         << ", fileName:" << desc << ", hapPath: " << hapPath;
525         newJsPandaFile->SetHapPath(hapPath.c_str());
526     }
527 
528     CString methodName = entryPoint.data();
529     if (newJsPandaFile->IsBundlePack()) {
530         // entryPoint maybe is _GLOBAL::func_main_watch to execute func_main_watch
531         auto pos = entryPoint.find_last_of("::");
532         if (pos != std::string_view::npos) {
533             methodName = entryPoint.substr(pos + 1);
534         } else {
535             // default use func_main_0 as entryPoint
536             methodName = JSPandaFile::ENTRY_FUNCTION_NAME;
537         }
538     }
539     if (newJsPandaFile->IsNewVersion() && vm->IsAsynTranslateClasses()) {
540         newJsPandaFile->TranslateClasses(thread, methodName);
541     } else {
542         PandaFileTranslator::TranslateClasses(thread, newJsPandaFile.get(), methodName);
543     }
544 
545     {
546         LockHolder lock(jsPandaFileLock_);
547         std::shared_ptr<JSPandaFile> jsPandaFile = FindJSPandaFileUnlocked(desc);
548         if (jsPandaFile != nullptr) {
549             newJsPandaFile.reset();
550             return jsPandaFile;
551         } else {
552             AddJSPandaFile(newJsPandaFile);
553             return newJsPandaFile;
554         }
555     }
556 }
557 
558 /*
559  * Check whether the file path can be loaded into pandafile, excluding bundle packaging and decompression paths
560  */
CheckFilePath(JSThread * thread,const CString & fileName)561 bool JSPandaFileManager::CheckFilePath(JSThread *thread, const CString &fileName)
562 {
563     std::shared_ptr<JSPandaFile> jsPandaFile = FindJSPandaFileUnlocked(fileName);
564     if (jsPandaFile != nullptr) {
565         return true;
566     }
567     EcmaVM *vm = thread->GetEcmaVM();
568     ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
569     if (!vm->IsBundlePack() && moduleManager->GetExecuteMode() == ModuleExecuteMode::ExecuteBufferMode) {
570         ResolveBufferCallback resolveBufferCallback = vm->GetResolveBufferCallback();
571         if (resolveBufferCallback == nullptr) {
572             LOG_FULL(ERROR) << "When checking file path, resolveBufferCallback is nullptr";
573             return false;
574         }
575         uint8_t *data = nullptr;
576         size_t dataSize = 0;
577         std::string errorMsg;
578         bool getBuffer = resolveBufferCallback(ModulePathHelper::ParseHapPath(fileName), &data, &dataSize, errorMsg);
579         if (!getBuffer) {
580             LOG_FULL(ERROR)
581                 << "When checking file path, resolveBufferCallback get buffer failed, errorMsg = " << errorMsg;
582             return false;
583         }
584     }
585     return true;
586 }
587 
GenerateJSPandafileFromBufferCache(JSThread * thread,const CString & filename,std::string_view entryPoint)588 std::shared_ptr<JSPandaFile> JSPandaFileManager::GenerateJSPandafileFromBufferCache(
589     JSThread *thread, const CString &filename, std::string_view entryPoint)
590 {
591     AbcBufferInfo bufferInfo =
592         thread->GetCurrentEcmaContext()->GetAbcBufferCache()->FindJSPandaFileInAbcBufferCache(filename);
593     if (bufferInfo.buffer_ == nullptr) {
594         return nullptr;
595     }
596     LOG_FULL(INFO) << "fileName was found in bufferFiles_.";
597     JSPandaFileManager *jsPandaFileManager = JSPandaFileManager::GetInstance();
598     if (bufferInfo.bufferType_ == AbcBufferType::SECURE_BUFFER) {
599         return jsPandaFileManager->LoadJSPandaFileSecure(
600             thread, filename, entryPoint, reinterpret_cast<uint8_t *>(bufferInfo.buffer_), bufferInfo.size_);
601     }
602     return jsPandaFileManager->LoadJSPandaFile(
603         thread, filename, entryPoint, bufferInfo.buffer_, bufferInfo.size_);
604 }
605 
AllocateBuffer(size_t size,bool isBundlePack,CreateMode mode)606 void *JSPandaFileManager::AllocateBuffer(size_t size, bool isBundlePack, CreateMode mode)
607 {
608     if (mode == CreateMode::DFX) {
609         return JSPandaFileAllocator::AllocateBuffer(size);
610     }
611     auto allocator = Runtime::GetInstance()->GetNativeAreaAllocator();
612     if (isBundlePack) {
613         return allocator->AllocateBuffer(size);
614     }
615     return allocator->NativeAreaPageMap(size);
616 }
617 
AllocateBuffer(size_t size)618 void *JSPandaFileManager::JSPandaFileAllocator::AllocateBuffer(size_t size)
619 {
620     if (size == 0) {
621         LOG_ECMA_MEM(FATAL) << "size must have a size bigger than 0";
622         UNREACHABLE();
623     }
624     if (size >= MALLOC_SIZE_LIMIT) {
625         LOG_ECMA_MEM(FATAL) << "size must be less than the maximum";
626         UNREACHABLE();
627     }
628     // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
629     void *ptr = malloc(size);
630     if (ptr == nullptr) {
631         LOG_ECMA_MEM(FATAL) << "malloc failed";
632         UNREACHABLE();
633     }
634 #if ECMASCRIPT_ENABLE_ZAP_MEM
635     if (memset_s(ptr, size, INVALID_VALUE, size) != EOK) {
636         LOG_ECMA_MEM(FATAL) << "memset_s failed";
637         UNREACHABLE();
638     }
639 #endif
640     return ptr;
641 }
642 
FreeBuffer(void * mem,size_t size,bool isBundlePack,CreateMode mode)643 void JSPandaFileManager::FreeBuffer(void *mem, size_t size, bool isBundlePack, CreateMode mode)
644 {
645     if (mode == CreateMode::DFX) {
646         return JSPandaFileAllocator::FreeBuffer(mem);
647     }
648     auto allocator = Runtime::GetInstance()->GetNativeAreaAllocator();
649     if (isBundlePack) {
650         return allocator->FreeBuffer(mem);
651     }
652     allocator->NativeAreaPageUnmap(mem, size);
653 }
654 
FreeBuffer(void * mem)655 void JSPandaFileManager::JSPandaFileAllocator::FreeBuffer(void *mem)
656 {
657     if (mem == nullptr) {
658         return;
659     }
660     // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
661     free(mem);
662 }
663 }  // namespace panda::ecmascript
664