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