• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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