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