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