• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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_PATCH_PATCH_LOADER_H
17 #define ECMASCRIPT_PATCH_PATCH_LOADER_H
18 
19 #include "ecmascript/jspandafile/js_pandafile.h"
20 #include "ecmascript/js_tagged_value.h"
21 #include "ecmascript/mem/c_containers.h"
22 #include "ecmascript/napi/include/jsnapi_internals.h"
23 
24 namespace panda::ecmascript {
25 using JSRecordInfo = JSPandaFile::JSRecordInfo;
26 using LiteralDataAccessor = panda_file::LiteralDataAccessor;
27 using LiteralValue = panda_file::LiteralDataAccessor::LiteralValue;
28 using LiteralTag = panda_file::LiteralTag;
29 class ConstantPool;
30 class JSThread;
31 class Method;
32 
33 struct BaseMethodIndex {
34     uint32_t constpoolNum {UINT32_MAX};
35     uint32_t constpoolIndex {UINT32_MAX};
36     uint32_t literalIndex {UINT32_MAX};
37     struct Hash {
operatorBaseMethodIndex::Hash38         std::size_t operator()(const BaseMethodIndex &baseMethodIndex) const
39         {
40             return std::hash<uint32_t>{}(baseMethodIndex.constpoolNum) ^ (std::hash<uint32_t>{}(
41                 baseMethodIndex.constpoolIndex) << 1) ^ std::hash<uint32_t>{}(baseMethodIndex.literalIndex);
42         }
43     };
44 
45     bool operator==(const BaseMethodIndex &baseMethodIndex) const
46     {
47         return constpoolNum == baseMethodIndex.constpoolNum && constpoolIndex == baseMethodIndex.constpoolIndex &&
48             literalIndex == baseMethodIndex.literalIndex;
49     }
50 };
51 
52 struct PatchMethodIndex {
53     CString recordName;
54     CString className;
55     CString methodName;
56     struct Hash {
operatorPatchMethodIndex::Hash57         std::size_t operator()(const PatchMethodIndex &patchMethodIndex) const
58         {
59             return std::hash<CString>{}(patchMethodIndex.recordName) ^
60                 std::hash<CString>{}(patchMethodIndex.className) ^ std::hash<CString>{}(patchMethodIndex.methodName);
61         }
62     };
63 
64     bool operator==(const PatchMethodIndex &patchMethodIndex) const
65     {
66         return recordName == patchMethodIndex.recordName && className == patchMethodIndex.className &&
67             methodName == patchMethodIndex.methodName;
68     }
69 };
70 
71 struct ReplacedMethod {
72     EntityId methodId;
73     CString fileName;
74     struct Hash {
operatorReplacedMethod::Hash75         std::size_t operator()(const ReplacedMethod &replacedMethod) const
76         {
77             return std::hash<EntityId>{}(replacedMethod.methodId) ^ std::hash<CString>{}(replacedMethod.fileName);
78         }
79     };
80 
81     bool operator==(const ReplacedMethod &replacedMethod) const
82     {
83         return methodId == replacedMethod.methodId && fileName == replacedMethod.fileName;
84     }
85 };
86 
87 
88 struct PatchInfo {
89     // patch file name.
90     CString patchFileName;
91     // patch methodLiterals for load patch, <recordName, <methodName, MethodLiteral>>
92     CUnorderedMap<PatchMethodIndex, MethodLiteral*, PatchMethodIndex::Hash> patchMethodLiterals;
93     // base method info for unload patch, <BaseMethodIndex, base MethodLiteral>
94     CUnorderedMap<BaseMethodIndex, MethodLiteral *, BaseMethodIndex::Hash> baseMethodInfo;
95     // save base constpool in global for avoid gc.
96     CVector<JSHandle<JSTaggedValue>> baseConstpools;
97     // patch replaced recordNames.
98     CUnorderedSet<CString> replacedRecordNames;
99     // patch replaced methods.
100     CUnorderedMap<ReplacedMethod, CString, ReplacedMethod::Hash> replacedPatchMethods;
101 };
102 
103 enum class StageOfHotReload : int32_t {
104     BEGIN_EXECUTE_PATCHMAIN = -1, // -1: For intercepting Evaluate()
105     INITIALIZE_STAGE_OF_HOTRELOAD, // 0 : initialize stageOfHotreload_ in js_thread.h
106     LOAD_END_EXECUTE_PATCHMAIN, // 1: for Interceptint get module var
107     UNLOAD_END_EXECUTE_PATCHMAIN // 2 :for execute abc normally
108 };
109 
110 enum class StageOfColdReload : int32_t {
111     NOT_COLD_RELOAD,
112     IS_COLD_RELOAD
113 };
114 
115 class PatchLoader {
116 public:
117     PatchLoader() = default;
118     ~PatchLoader() = default;
119     NO_COPY_SEMANTIC(PatchLoader);
120     NO_MOVE_SEMANTIC(PatchLoader);
121 
122     static PatchErrorCode LoadPatchInternal(JSThread *thread, const JSPandaFile *baseFile,
123                                             const JSPandaFile *patchFile, PatchInfo &patchInfo,
124                                             const CMap<uint32_t, CString> &baseClassInfo);
125     static PatchErrorCode UnloadPatchInternal(JSThread *thread, const CString &patchFileName,
126                                               const CString &baseFileName, PatchInfo &patchInfo);
127 
128     static MethodLiteral *FindSameMethod(PatchInfo &patchInfo, const JSPandaFile *baseFile,
129                                          EntityId baseMethodId, const CMap<uint32_t, CString> &baseClassInfo);
130     static void ExecuteFuncOrPatchMain(
131         JSThread *thread, const JSPandaFile *jsPandaFile, const PatchInfo &patchInfo, bool loadPatch = true);
132     static CMap<uint32_t, CString> CollectClassInfo(const JSPandaFile *jsPandaFile);
133     static void UpdateModuleForColdPatch(
134         JSThread *thread, EntityId methodId, CString &recordName, bool hasModule = true);
135     static void UpdateJSFunction(JSThread *thread, PatchInfo &patchInfo);
136 
137 private:
138     static PatchInfo GeneratePatchInfo(const JSPandaFile *patchFile);
139     static CString GetRealName(const JSPandaFile *jsPandaFile, EntityId entityId, CString &className);
140     static void FindAndReplaceSameMethod(JSThread *thread,
141                                          const JSPandaFile *baseFile,
142                                          const JSPandaFile *patchFile,
143                                          PatchInfo &patchInfo,
144                                          const CMap<uint32_t, CString> &baseClassInfo);
145     static void SaveBaseMethodInfo(PatchInfo &patchInfo, const JSPandaFile *baseFile,
146                                    EntityId baseMethodId, const BaseMethodIndex &indexs);
147     static void ReplaceMethod(JSThread *thread,
148                               Method *destMethod,
149                               MethodLiteral *srcMethodLiteral,
150                               JSTaggedValue srcConstpool);
151 
152     static void ClearPatchInfo(JSThread *thread, const CString &patchFileName);
153 
154     static Method *GetPatchMethod(JSThread *thread,
155         const BaseMethodIndex &methodIndex, const JSTaggedValue baseConstpool);
156     static void FindAndReplaceClassLiteral(JSThread *thread, const JSPandaFile *baseFile,
157                                            const JSPandaFile *patchFile, JSTaggedValue constpoolValue,
158                                            PatchInfo &patchInfo, uint32_t constpoolIndex,
159                                            uint32_t constpoolNum, const CMap<uint32_t, CString> &baseClassInfo);
160 };
161 }  // namespace panda::ecmascript
162 #endif // ECMASCRIPT_PATCH_PATCH_LOADER_H
163