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