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