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