1 /* 2 * Copyright (c) 2022-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 #ifndef ECMASCRIPT_JSPANDAFILE_JS_PANDAFILE_H 17 #define ECMASCRIPT_JSPANDAFILE_JS_PANDAFILE_H 18 19 #include "ecmascript/common.h" 20 #include "ecmascript/jspandafile/constpool_value.h" 21 #include "ecmascript/jspandafile/method_literal.h" 22 #include "ecmascript/log_wrapper.h" 23 #include "ecmascript/mem/c_containers.h" 24 #include "ecmascript/platform/mutex.h" 25 #include "ecmascript/taskpool/task.h" 26 27 #include "libpandafile/file-inl.h" 28 #include "libpandafile/file_items.h" 29 #include "libpandafile/literal_data_accessor.h" 30 31 namespace panda { 32 namespace ecmascript { 33 class JSPandaFile { 34 public: 35 struct JSRecordInfo { 36 uint32_t mainMethodIndex {0}; 37 bool isCjs {false}; 38 bool isJson {false}; 39 bool isSharedModule {false}; 40 int jsonStringId {-1}; 41 CUnorderedSet<const EcmaVM *> vmListOfParsedConstPool; 42 int moduleRecordIdx {-1}; 43 bool hasTopLevelAwait {false}; 44 CUnorderedMap<uint32_t, uint64_t> constpoolMap; 45 uint32_t lazyImportIdx {0}; 46 uint32_t classId {CLASSID_OFFSET_NOT_FOUND}; 47 CString npmPackageName; 48 SetParsedConstpoolVMJSRecordInfo49 void SetParsedConstpoolVM(const EcmaVM *vm) 50 { 51 vmListOfParsedConstPool.insert(vm); 52 } 53 IsParsedConstpoolOfCurrentVMJSRecordInfo54 bool IsParsedConstpoolOfCurrentVM(const EcmaVM *vm) const 55 { 56 auto iter = vmListOfParsedConstPool.find(vm); 57 if (iter != vmListOfParsedConstPool.end()) { 58 return true; 59 } 60 return false; 61 } 62 }; 63 static constexpr char ENTRY_FUNCTION_NAME[] = "func_main_0"; 64 static constexpr char ENTRY_MAIN_FUNCTION[] = "_GLOBAL::func_main_0"; 65 static constexpr char PATCH_MAIN_FUNCTION[] = "_GLOBAL::patch_main_0"; 66 static constexpr char PATCH_FUNCTION_NAME_0[] = "patch_main_0"; 67 static constexpr char PATCH_FUNCTION_NAME_1[] = "patch_main_1"; 68 69 static constexpr char MODULE_CLASS[] = "L_ESModuleRecord;"; 70 static constexpr char COMMONJS_CLASS[] = "L_CommonJsRecord;"; 71 static constexpr char HASTLA_CLASS[] = "L_HasTopLevelAwait;"; 72 73 static constexpr char IS_COMMON_JS[] = "isCommonjs"; 74 static constexpr char IS_JSON_CONTENT[] = "jsonFileContent"; 75 static constexpr char MODULE_RECORD_IDX[] = "moduleRecordIdx"; 76 static constexpr char IS_SHARED_MODULE[] = "isSharedModule"; 77 static constexpr char HAS_TOP_LEVEL_AWAIT[] = "hasTopLevelAwait"; 78 static constexpr char LAZY_IMPORT[] = "moduleRequestPhaseIdx"; 79 static constexpr char PACKAGE_NAME[] = "pkgName@"; 80 static constexpr char MERGE_ABC_NAME[] = "modules.abc"; 81 static constexpr char NPM_PATH_SEGMENT[] = "node_modules"; 82 static constexpr char PACKAGE_PATH_SEGMENT[] = "pkg_modules"; 83 static constexpr char BUNDLE_INSTALL_PATH[] = "/data/storage/el1/bundle/"; 84 static constexpr int PACKAGE_NAME_LEN = 8; 85 static constexpr int TYPE_SUMMARY_OFFSET_NOT_FOUND = 0; 86 static constexpr int CLASSID_OFFSET_NOT_FOUND = 0; 87 static constexpr int32_t PF_OFFSET = 0; 88 89 JSPandaFile(const panda_file::File *pf, const CString &descriptor); 90 ~JSPandaFile(); 91 92 class TranslateClassesTask : public Task { 93 public: TranslateClassesTask(int32_t id,JSThread * thread,JSPandaFile * jsPandaFile,const std::shared_ptr<CString> & methodNamePtr)94 TranslateClassesTask(int32_t id, JSThread *thread, JSPandaFile *jsPandaFile, 95 const std::shared_ptr<CString> &methodNamePtr) 96 : Task(id), thread_(thread), jsPandaFile_(jsPandaFile), methodNamePtr_(methodNamePtr) {}; 97 ~TranslateClassesTask() override = default; 98 bool Run(uint32_t threadIndex) override; 99 100 NO_COPY_SEMANTIC(TranslateClassesTask); 101 NO_MOVE_SEMANTIC(TranslateClassesTask); 102 103 private: 104 JSThread *thread_ {nullptr}; 105 JSPandaFile *jsPandaFile_ {nullptr}; 106 std::shared_ptr<CString> methodNamePtr_; 107 }; 108 GetJSPandaFileDesc()109 const CString &GetJSPandaFileDesc() const 110 { 111 return desc_; 112 } 113 114 CString PUBLIC_API GetNormalizedFileDesc() const; 115 SetHapPath(const CString & hapPath)116 void SetHapPath(const CString &hapPath) 117 { 118 hapPath_ = hapPath; 119 } 120 GetJSPandaFileHapPath()121 const CString &GetJSPandaFileHapPath() const 122 { 123 return hapPath_; 124 } 125 126 static CString PUBLIC_API GetNormalizedFileDesc(const CString &desc); 127 GetChecksum()128 uint32_t GetChecksum() const 129 { 130 return checksum_; 131 } 132 GetPandaFile()133 const panda_file::File *GetPandaFile() const 134 { 135 return pf_; 136 } 137 138 std::pair<std::string_view, bool> GetMethodName(EntityId methodId); 139 std::pair<std::string_view, bool> GetCpuProfilerMethodName(EntityId methodId) const; 140 CString GetRecordName(EntityId methodId); 141 CString PUBLIC_API GetRecordNameWithBundlePack(EntityId methodIdx); 142 GetMethodLiterals()143 MethodLiteral* GetMethodLiterals() const 144 { 145 return methodLiterals_; 146 } 147 SetMethodLiteralToMap(MethodLiteral * methodLiteral)148 void SetMethodLiteralToMap(MethodLiteral *methodLiteral) 149 { 150 ASSERT(methodLiteral != nullptr); 151 methodLiteralMap_.emplace(methodLiteral->GetMethodId().GetOffset(), methodLiteral); 152 } 153 GetMethodLiteralMap()154 const std::unordered_map<uint32_t, MethodLiteral *> &GetMethodLiteralMap() const 155 { 156 return methodLiteralMap_; 157 } 158 GetMethodLiteralByIndex(uint32_t index)159 MethodLiteral *GetMethodLiteralByIndex(uint32_t index) const 160 { 161 auto info = methodLiteralMap_.find(index); 162 if (info != methodLiteralMap_.end()) { 163 return info->second; 164 } 165 return nullptr; 166 } 167 GetNumMethods()168 uint32_t GetNumMethods() const 169 { 170 return numMethods_; 171 } 172 GetConstpoolIndex()173 uint32_t GetConstpoolIndex() const 174 { 175 return constpoolIndex_; 176 } 177 178 uint32_t GetMainMethodIndex(const CString &recordName = ENTRY_FUNCTION_NAME) const 179 { 180 if (IsBundlePack()) { 181 return jsRecordInfo_.begin()->second->mainMethodIndex; 182 } 183 auto info = jsRecordInfo_.find(recordName); 184 if (info != jsRecordInfo_.end()) { 185 return info->second->mainMethodIndex; 186 } 187 LOG_ECMA(ERROR) << "can not get main method index: " << recordName; 188 return 0; 189 } 190 GetConstpoolMapByReocrd(const CString & recordName)191 const CUnorderedMap<uint32_t, uint64_t> *GetConstpoolMapByReocrd(const CString &recordName) const 192 { 193 auto info = jsRecordInfo_.find(recordName); 194 if (info != jsRecordInfo_.end()) { 195 return &info->second->constpoolMap; 196 } 197 LOG_FULL(FATAL) << "find entryPoint failed: " << recordName; 198 UNREACHABLE(); 199 } 200 GetConstpoolMap()201 const CUnorderedMap<uint32_t, uint64_t> &GetConstpoolMap() const 202 { 203 return constpoolMap_; 204 } 205 206 uint32_t PUBLIC_API GetOrInsertConstantPool(ConstPoolType type, uint32_t offset, 207 const CUnorderedMap<uint32_t, uint64_t> *constpoolMap = nullptr); 208 209 void UpdateMainMethodIndex(uint32_t mainMethodIndex, const CString &recordName = ENTRY_FUNCTION_NAME) 210 { 211 LockHolder lock(jsRecordInfoMutex_); 212 if (IsBundlePack()) { 213 jsRecordInfo_.begin()->second->mainMethodIndex = mainMethodIndex; 214 } else { 215 auto info = jsRecordInfo_.find(recordName); 216 if (info != jsRecordInfo_.end()) { 217 info->second->mainMethodIndex = mainMethodIndex; 218 } 219 } 220 } 221 222 PUBLIC_API MethodLiteral *FindMethodLiteral(uint32_t offset) const; 223 224 int GetModuleRecordIdx(const CString &recordName = ENTRY_FUNCTION_NAME) const 225 { 226 if (IsBundlePack()) { 227 return jsRecordInfo_.begin()->second->moduleRecordIdx; 228 } 229 auto info = jsRecordInfo_.find(recordName); 230 if (info != jsRecordInfo_.end()) { 231 return info->second->moduleRecordIdx; 232 } 233 // The array subscript will not have a negative number, and returning -1 means the search failed 234 return -1; 235 } 236 237 int GetHasTopLevelAwait(const CString &recordName = ENTRY_FUNCTION_NAME) const 238 { 239 if (IsBundlePack()) { 240 return jsRecordInfo_.begin()->second->hasTopLevelAwait; 241 } 242 auto info = jsRecordInfo_.find(recordName); 243 if (info != jsRecordInfo_.end()) { 244 return info->second->hasTopLevelAwait; 245 } 246 return false; 247 } 248 GetClasses()249 Span<const uint32_t> GetClasses() const 250 { 251 return pf_->GetClasses(); 252 } 253 IsExternal(panda_file::File::EntityId id)254 inline bool IsExternal(panda_file::File::EntityId id) const 255 { 256 return pf_->IsExternal(id); 257 } 258 Contain(uint8_t * data)259 inline bool Contain(uint8_t *data) const 260 { 261 uintptr_t header = ToUintPtr(GetHeader()); 262 uintptr_t dataPointer = ToUintPtr(data); 263 if (header < dataPointer && dataPointer < (header + GetFileSize())) { 264 return true; 265 } 266 return false; 267 } 268 GetStringData(panda_file::File::EntityId id)269 inline panda_file::File::StringData GetStringData(panda_file::File::EntityId id) const 270 { 271 return pf_->GetStringData(id); 272 } 273 ResolveMethodIndex(panda_file::File::EntityId id,uint16_t idx)274 panda_file::File::EntityId ResolveMethodIndex(panda_file::File::EntityId id, uint16_t idx) const 275 { 276 return pf_->ResolveMethodIndex(id, idx); 277 } 278 GetLiteralDataAccessor()279 panda_file::LiteralDataAccessor GetLiteralDataAccessor() const 280 { 281 EntityId literalArraysId = pf_->GetLiteralArraysId(); 282 panda_file::LiteralDataAccessor lda(*pf_, literalArraysId); 283 return lda; 284 } 285 GetConstpoolNum()286 uint32_t GetConstpoolNum() const 287 { 288 return pf_->GetHeader()->num_indexes; 289 } 290 GetMethodIndex(const panda_file::File::IndexHeader * indexHeader)291 Span<const panda_file::File::EntityId> GetMethodIndex(const panda_file::File::IndexHeader *indexHeader) const 292 { 293 return pf_->GetMethodIndex(indexHeader); 294 } 295 GetHeader()296 const void *GetHeader() const 297 { 298 return static_cast<const void *>(pf_->GetHeader()); 299 } 300 GetFileSize()301 uint32_t GetFileSize() const 302 { 303 return pf_->GetHeader()->file_size; 304 } 305 306 bool CheckAndGetRecordInfo(const CString &recordName, JSRecordInfo **recordInfo) const; 307 308 const JSRecordInfo* GetRecordInfo(const CString &recordName); 309 310 CString GetJsonStringId(const JSRecordInfo &jsRecordInfo) const; 311 IsModule(const JSRecordInfo * jsRecordInfo)312 bool PUBLIC_API IsModule(const JSRecordInfo *jsRecordInfo) const 313 { 314 return jsRecordInfo->moduleRecordIdx != -1; 315 } 316 IsCjs(const JSRecordInfo * jsRecordInfo)317 bool IsCjs(const JSRecordInfo *jsRecordInfo) const 318 { 319 return jsRecordInfo->isCjs; 320 } 321 IsJson(const JSRecordInfo * jsRecordInfo)322 bool IsJson(const JSRecordInfo *jsRecordInfo) const 323 { 324 return jsRecordInfo->isJson; 325 } 326 IsSharedModule(const JSRecordInfo * jsRecordInfo)327 bool IsSharedModule(const JSRecordInfo *jsRecordInfo) const 328 { 329 return jsRecordInfo->isSharedModule; 330 } 331 IsBundlePack()332 bool IsBundlePack() const 333 { 334 return isBundlePack_; 335 } 336 IsLoadedAOT()337 bool IsLoadedAOT() const 338 { 339 return (GetAOTFileInfoIndex() != INVALID_INDEX); 340 } 341 GetFileUniqId()342 uint32_t GetFileUniqId() const 343 { 344 return static_cast<uint32_t>(GetPandaFile()->GetUniqId()); 345 } 346 IsNewVersion()347 bool IsNewVersion() const 348 { 349 return isNewVersion_; 350 } 351 HasRecord(const CString & recordName)352 bool HasRecord(const CString &recordName) const 353 { 354 return jsRecordInfo_.find(recordName) != jsRecordInfo_.end(); 355 } 356 FindRecordInfo(const CString & recordName)357 JSRecordInfo &FindRecordInfo(const CString &recordName) 358 { 359 auto info = jsRecordInfo_.find(recordName); 360 // check entry name, fix framework abc find recordName fail bug 361 if (recordName == "_GLOBAL") { 362 info = jsRecordInfo_.find(ENTRY_FUNCTION_NAME); 363 } 364 if (info == jsRecordInfo_.end()) { 365 LOG_FULL(FATAL) << "find recordName failed: " << recordName; 366 UNREACHABLE(); 367 } 368 return *(info->second); 369 } 370 371 // note : it only uses in TDD InsertJSRecordInfo(const CString & recordName)372 void InsertJSRecordInfo(const CString &recordName) 373 { 374 JSRecordInfo* info = new JSRecordInfo(); 375 jsRecordInfo_.insert({recordName, info}); 376 } 377 GetJSRecordInfo()378 const CUnorderedMap<CString, JSRecordInfo*> &GetJSRecordInfo() const 379 { 380 return jsRecordInfo_; 381 } 382 ParseEntryPoint(const CString & desc)383 static CString ParseEntryPoint(const CString &desc) 384 { 385 return desc.substr(1, desc.size() - 2); // 2 : skip symbol "L" and ";" 386 } 387 388 void CheckIsBundlePack(); 389 void CheckIsRecordWithBundleName(const CString &entry); IsRecordWithBundleName()390 bool IsRecordWithBundleName() const 391 { 392 return isRecordWithBundleName_; 393 } 394 CString GetEntryPoint(const CString &recordName) const; 395 CString GetRecordName(const CString &entryPoint) const; 396 bool FindOhmUrlInPF(const CString &recordName, CString &entryPoint) const; GetAOTFileInfoIndex()397 uint32_t GetAOTFileInfoIndex() const 398 { 399 return anFileInfoIndex_; 400 } 401 SetAOTFileInfoIndex(uint32_t index)402 void SetAOTFileInfoIndex(uint32_t index) 403 { 404 if (IsLoadedAOT()) { 405 LOG_ECMA(ERROR) << "Set Aot file info index failed. desc: " << GetJSPandaFileDesc() 406 << ", anFileIndex: " << anFileInfoIndex_ << " vs " << index; 407 return; 408 } 409 anFileInfoIndex_ = index; 410 } 411 IsEntryOrPatch(const CString & name)412 static bool IsEntryOrPatch(const CString &name) 413 { 414 return (name == PATCH_FUNCTION_NAME_0) || (name == ENTRY_FUNCTION_NAME); 415 } 416 DeleteParsedConstpoolVM(const EcmaVM * vm)417 void DeleteParsedConstpoolVM(const EcmaVM *vm) 418 { 419 for (auto &recordInfo : jsRecordInfo_) { 420 recordInfo.second->vmListOfParsedConstPool.erase(vm); 421 } 422 } 423 static FunctionKind PUBLIC_API GetFunctionKind(panda_file::FunctionKind funcKind); 424 static FunctionKind GetFunctionKind(ConstPoolType type); IsSendableFunctionKind(panda_file::FunctionKind funcKind)425 static bool PUBLIC_API IsSendableFunctionKind(panda_file::FunctionKind funcKind) 426 { 427 return (static_cast<uint32_t>(funcKind) & SENDABLE_FUNCTION_MASK) != 0; 428 } 429 430 bool PUBLIC_API IsFirstMergedAbc() const; GetBase()431 const void *GetBase() const 432 { 433 return static_cast<const void *>(pf_->GetBase()); 434 } 435 436 void ClearNameMap(); 437 438 void TranslateClasses(JSThread *thread, const CString &methodName); 439 440 private: 441 void InitializeUnMergedPF(); 442 void InitializeMergedPF(); 443 444 void WaitTranslateClassTaskFinished(); 445 446 void NotifyTranslateClassTaskCompleted(); 447 448 void IncreaseTaskCount(); 449 450 void TranslateClass(JSThread *thread, const CString &methodName); 451 452 void PostInitializeMethodTask(JSThread *thread, const std::shared_ptr<CString> &methodNamePtr); 453 454 void ReduceTaskCount(); 455 456 void SetAllMethodLiteralToMap(); 457 458 size_t GetClassAndMethodIndex(size_t *methodIdx); 459 460 static constexpr size_t VERSION_SIZE = 4; 461 static constexpr std::array<uint8_t, VERSION_SIZE> OLD_VERSION {0, 0, 0, 2}; 462 static constexpr uint32_t SENDABLE_FUNCTION_MASK = 1 << 3; 463 464 // please add member after *pf_. static constexpr int32_t PF_OFFSET = 0. 465 const panda_file::File *pf_ {nullptr}; 466 CString hapPath_; 467 uint32_t constpoolIndex_ {0}; 468 uint32_t checksum_ {0}; 469 std::unordered_map<uint32_t, MethodLiteral *> methodLiteralMap_; 470 std::unordered_map<uint32_t, panda_file::File::StringData> methodNameMap_; 471 CUnorderedMap<uint32_t, CString> recordNameMap_; 472 Mutex methodNameMapMutex_; 473 Mutex recordNameMapMutex_; 474 Mutex waitTranslateClassFinishedMutex_; 475 Mutex classIndexMutex_; 476 Mutex jsRecordInfoMutex_; 477 ConditionVariable waitTranslateClassFinishedCV_; 478 uint32_t runningTaskCount_ {0}; 479 size_t classIndex_ {0}; 480 size_t methodIndex_ {0}; 481 482 CUnorderedMap<uint32_t, uint64_t> constpoolMap_; 483 uint32_t numMethods_ {0}; 484 uint32_t numClasses_ {0}; 485 MethodLiteral *methodLiterals_ {nullptr}; 486 CString desc_; 487 uint32_t anFileInfoIndex_ {INVALID_INDEX}; 488 bool isNewVersion_ {false}; 489 490 // marge abc 491 bool isBundlePack_ {true}; // isBundlePack means app compile mode is JSBundle 492 CUnorderedMap<CString, JSRecordInfo*> jsRecordInfo_; 493 CUnorderedMap<CString, CString> npmEntries_; 494 bool isRecordWithBundleName_ {true}; 495 static bool loadedFirstPandaFile; 496 bool isFirstPandafile_{false}; 497 }; 498 } // namespace ecmascript 499 } // namespace panda 500 #endif // ECMASCRIPT_JSPANDAFILE_JS_PANDAFILE_H 501