1 /* 2 * Copyright (c) 2025 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_COMPILER_LAZY_DEOPT_DEPENDENCY_H 17 #define ECMASCRIPT_COMPILER_LAZY_DEOPT_DEPENDENCY_H 18 19 #include "ecmascript/common.h" 20 #include "ecmascript/compiler/pgo_type/pgo_type_manager.h" 21 #include "ecmascript/dependent_infos.h" 22 #include "ecmascript/js_hclass.h" 23 #include "ecmascript/js_thread.h" 24 25 namespace panda::ecmascript::kungfu { 26 27 using DependentState = DependentInfos::DependentState; 28 using DependentStateCollection = DependentInfos::DependentStateCollection; 29 class CombinedDependencies { 30 public: CombinedDependencies(GlobalEnv * globalEnv)31 CombinedDependencies(GlobalEnv *globalEnv) 32 { 33 globalEnv_ = globalEnv; 34 } 35 NO_COPY_SEMANTIC(CombinedDependencies); 36 NO_MOVE_SEMANTIC(CombinedDependencies); 37 38 void Register(JSHClass *hclass, DependentState state); 39 void Register(uint32_t detectorID, DependentState state); 40 void Register(DependentState state); 41 42 void InstallAll(JSThread *thread, JSHandle<JSTaggedValue> jsFunc); 43 44 private: 45 std::map<JSHClass *, DependentStateCollection> deps_; // hclass, collection 46 std::map<uint32_t, DependentStateCollection> detectorDeps_; // detectorID_, collection 47 GlobalEnv *globalEnv_; 48 DependentStateCollection threadDeps_ {0}; 49 }; 50 51 enum class LazyDeoptDependencyKind : uint32_t { 52 STABLE_HCLASS, // Once the HClass undergoes transition, "isStable" bit remains false permanently 53 NOT_PROTOTYPE_HCLASS, // Once the HClass becomes prototype, "isPrototype" bit remains true permanently 54 DETECTOR, 55 NOT_HOT_RELOAD_PATCHMAIN, 56 }; 57 58 class LazyDeoptDependency { 59 public: LazyDeoptDependency(LazyDeoptDependencyKind kind)60 explicit LazyDeoptDependency(LazyDeoptDependencyKind kind) : kind_(kind) {} 61 virtual ~LazyDeoptDependency() = default; 62 63 virtual bool IsValid() const = 0; 64 virtual void Install(CombinedDependencies *combinedDeps) const = 0; 65 private: 66 [[maybe_unused]]LazyDeoptDependencyKind kind_; 67 }; 68 69 class DetectorDependency final : public LazyDeoptDependency { 70 public: DetectorDependency(uint32_t detectorID,GlobalEnv * globalEnv)71 DetectorDependency (uint32_t detectorID, GlobalEnv *globalEnv) 72 : LazyDeoptDependency(LazyDeoptDependencyKind::DETECTOR), 73 detectorID_(detectorID), globalEnv_(globalEnv) {} 74 IsValid()75 bool IsValid() const override 76 { 77 return globalEnv_->GetDetectorValue(detectorID_); 78 } 79 Install(CombinedDependencies * combinedDeps)80 void Install(CombinedDependencies *combinedDeps) const override 81 { 82 ASSERT(IsValid()); 83 combinedDeps->Register(detectorID_, DependentState::DETECTOR_CHECK); 84 } 85 86 private: 87 uint32_t detectorID_; 88 GlobalEnv *globalEnv_; 89 }; 90 91 class NotPrototypeDependency final : public LazyDeoptDependency { 92 public: NotPrototypeDependency(JSHClass * hclass)93 NotPrototypeDependency(JSHClass *hclass) 94 : LazyDeoptDependency(LazyDeoptDependencyKind::NOT_PROTOTYPE_HCLASS), 95 hclass_(hclass) {} 96 IsValid()97 bool IsValid() const override 98 { 99 return !hclass_->IsPrototype(); 100 } 101 Install(CombinedDependencies * combinedDeps)102 void Install(CombinedDependencies *combinedDeps) const override 103 { 104 ASSERT(IsValid()); 105 combinedDeps->Register(hclass_, DependentState::IS_PROTOTYPE_CHECK); 106 } 107 108 private: 109 JSHClass *hclass_ {nullptr}; 110 }; 111 112 class StableHClassDependency final : public LazyDeoptDependency { 113 public: StableHClassDependency(JSHClass * hclass)114 StableHClassDependency(JSHClass *hclass) 115 : LazyDeoptDependency(LazyDeoptDependencyKind::STABLE_HCLASS), 116 hclass_(hclass) {} 117 IsValid(JSHClass * hclass)118 static bool IsValid(JSHClass *hclass) 119 { 120 return !hclass->IsDictionaryMode() && hclass->IsStable(); 121 } 122 IsValid()123 bool IsValid() const override 124 { 125 return IsValid(hclass_); 126 } 127 Install(CombinedDependencies * combinedDeps)128 void Install(CombinedDependencies *combinedDeps) const override 129 { 130 ASSERT(IsValid()); 131 combinedDeps->Register(hclass_, DependentState::PROTOTYPE_CHECK); 132 } 133 134 private: 135 JSHClass *hclass_ {nullptr}; 136 }; 137 138 class NotHotReloadDependency final : public LazyDeoptDependency { 139 public: NotHotReloadDependency(JSThread * thread)140 NotHotReloadDependency(JSThread *thread) 141 : LazyDeoptDependency(LazyDeoptDependencyKind::NOT_HOT_RELOAD_PATCHMAIN), thread_(thread) {} 142 IsValid()143 bool IsValid() const override 144 { 145 return thread_->GetStageOfHotReload() != StageOfHotReload::LOAD_END_EXECUTE_PATCHMAIN; 146 } 147 Install(CombinedDependencies * combinedDeps)148 void Install(CombinedDependencies *combinedDeps) const override 149 { 150 ASSERT(IsValid()); 151 combinedDeps->Register(DependentState::HOTRELOAD_PATCHMAIN); 152 } 153 154 private: 155 JSThread *thread_ {nullptr}; 156 }; 157 158 class PUBLIC_API LazyDeoptAllDependencies { 159 public: 160 LazyDeoptAllDependencies() = default; ~LazyDeoptAllDependencies()161 ~LazyDeoptAllDependencies() 162 { 163 Clear(); 164 } 165 166 static bool InitializeProtoChainForDependency(JSThread *thread, JSHClass *receiverHClass, 167 JSHClass *&holderHClass, GlobalEnv *globalEnv, 168 JSTaggedValue ¤t); 169 170 static bool CheckStableProtoChain(JSThread *thread, JSHClass *receiverHClass, 171 JSHClass *holderHClass, 172 GlobalEnv *globalEnv); 173 static bool CheckStableHClass(JSHClass *hclass); 174 175 bool DependOnArrayDetector(GlobalEnv *globalEnv); 176 bool DependOnDetector(uint32_t detectorID, GlobalEnv *globalEnv); 177 bool DependOnNotPrototype(JSHClass *hclass); 178 bool DependOnStableHClass(JSHClass *hclass); 179 bool DependOnStableProtoChain(JSThread *thread, JSHClass *receiverHClass, 180 JSHClass *holderHClass, 181 GlobalEnv *globalEnv = nullptr); 182 bool DependOnNotHotReloadPatchMain(JSThread *thread); 183 bool PreInstall(JSThread *thread); 184 PUBLIC_API static bool Commit(LazyDeoptAllDependencies *dependencies, 185 JSThread *thread, JSTaggedValue jsFunc); 186 Clear()187 void Clear() 188 { 189 for (auto& dep : dependencies_) { 190 delete dep; 191 } 192 dependencies_.clear(); 193 } 194 SetGlobalEnv(GlobalEnv * globalEnv)195 void SetGlobalEnv(GlobalEnv *globalEnv) 196 { 197 globalEnv_ = globalEnv; 198 } 199 GetGlobalEnv()200 GlobalEnv* GetGlobalEnv() 201 { 202 return globalEnv_; 203 } 204 private: 205 void RegisterDependency(const LazyDeoptDependency *dependency); 206 std::vector<const LazyDeoptDependency *> dependencies_; 207 GlobalEnv *globalEnv_; 208 }; 209 } // namespace panda::ecmascript::kungfu 210 #endif // ECMASCRIPT_COMPILER_LAZY_DEOPT_DEPENDENCY_H 211