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