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