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