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