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