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