• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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_IC_PROFILE_TYPE_INFO_H
17 #define ECMASCRIPT_IC_PROFILE_TYPE_INFO_H
18 
19 #include "ecmascript/js_function.h"
20 #include "ecmascript/tagged_array.h"
21 
22 namespace panda::ecmascript {
23 enum class ICKind : uint32_t {
24     NamedLoadIC,
25     NamedStoreIC,
26     LoadIC,
27     StoreIC,
28     NamedGlobalLoadIC,
29     NamedGlobalStoreIC,
30     NamedGlobalTryLoadIC,
31     NamedGlobalTryStoreIC,
32     GlobalLoadIC,
33     GlobalStoreIC,
34 };
35 
IsNamedGlobalIC(ICKind kind)36 static inline bool IsNamedGlobalIC(ICKind kind)
37 {
38     return (kind == ICKind::NamedGlobalLoadIC) || (kind == ICKind::NamedGlobalStoreIC) ||
39            (kind == ICKind::NamedGlobalTryLoadIC) || (kind == ICKind::NamedGlobalTryStoreIC);
40 }
41 
IsValueGlobalIC(ICKind kind)42 static inline bool IsValueGlobalIC(ICKind kind)
43 {
44     return (kind == ICKind::GlobalLoadIC) || (kind == ICKind::GlobalStoreIC);
45 }
46 
IsValueNormalIC(ICKind kind)47 static inline bool IsValueNormalIC(ICKind kind)
48 {
49     return (kind == ICKind::LoadIC) || (kind == ICKind::StoreIC);
50 }
51 
IsValueIC(ICKind kind)52 static inline bool IsValueIC(ICKind kind)
53 {
54     return IsValueNormalIC(kind) || IsValueGlobalIC(kind);
55 }
56 
IsNamedNormalIC(ICKind kind)57 static inline bool IsNamedNormalIC(ICKind kind)
58 {
59     return (kind == ICKind::NamedLoadIC) || (kind == ICKind::NamedStoreIC);
60 }
61 
IsNamedIC(ICKind kind)62 static inline bool IsNamedIC(ICKind kind)
63 {
64     return IsNamedNormalIC(kind) || IsNamedGlobalIC(kind);
65 }
66 
IsGlobalLoadIC(ICKind kind)67 static inline bool IsGlobalLoadIC(ICKind kind)
68 {
69     return (kind == ICKind::NamedGlobalLoadIC) || (kind == ICKind::GlobalLoadIC) ||
70            (kind == ICKind::NamedGlobalTryLoadIC);
71 }
72 
IsGlobalStoreIC(ICKind kind)73 static inline bool IsGlobalStoreIC(ICKind kind)
74 {
75     return (kind == ICKind::NamedGlobalStoreIC) || (kind == ICKind::GlobalStoreIC) ||
76            (kind == ICKind::NamedGlobalTryStoreIC);
77 }
78 
IsGlobalIC(ICKind kind)79 static inline bool IsGlobalIC(ICKind kind)
80 {
81     return IsValueGlobalIC(kind) || IsNamedGlobalIC(kind);
82 }
83 
84 std::string ICKindToString(ICKind kind);
85 
86 class ProfileTypeAccessorLockScope {
87 public:
ProfileTypeAccessorLockScope(JSThread * thread)88     ProfileTypeAccessorLockScope(JSThread *thread)
89     {
90         if (thread->GetEcmaVM()->IsEnableFastJit() || thread->GetEcmaVM()->IsEnableBaselineJit()) {
91             lockHolder_.emplace(thread->GetProfileTypeAccessorLock());
92         }
93     }
94 
95 private:
96     std::optional<LockHolder> lockHolder_;
97 };
98 
99 /**
100  *              ProfileTypeInfo
101  *      +--------------------------------+
102  *      |           ic slot              |
103  *      |            .....               |
104  *      +--------------------------------+
105  *      |        64 bits jit osr         |
106  *      |      tagged array address      |
107  *      +--------------------------------+
108  *      |    low 32 bits(PeriodCount)    |
109  *      |    hight 32 bits(jit hotness)  |
110  *      +--------------------------------+
111  *      |    low 32 bits(osr hotness)    |
112  *      | hight 32 bits(baseline hotness)|
113  *      +--------------------------------+
114  */
115 class ProfileTypeInfo : public TaggedArray {
116 public:
117     static const uint32_t MAX_FUNC_CACHE_INDEX = std::numeric_limits<uint32_t>::max();
118     static constexpr uint32_t INVALID_SLOT_INDEX = 0xFF;
119     static constexpr uint32_t MAX_SLOT_INDEX = 0xFFFF;
120     static constexpr size_t BIT_FIELD_INDEX = 2;
121     static constexpr size_t JIT_OSR_INDEX = 3;
122     static constexpr size_t RESERVED_LENGTH = JIT_OSR_INDEX;
123     static constexpr size_t INITIAL_PERIOD_INDEX = 0;
124     static constexpr size_t PRE_DUMP_PERIOD_INDEX = 1;
125     static constexpr size_t DUMP_PERIOD_INDEX = 2;
126     static constexpr size_t BIG_METHOD_PERIOD_INDEX = 3;
127     static constexpr size_t INITIAL_OSR_HOTNESS_THRESHOLD = 0;
128     static constexpr size_t INITIAL_OSR_HOTNESS_CNT = 0;
129     static constexpr size_t INITIAL_JIT_CALL_THRESHOLD = 0;
130     static constexpr size_t INITIAL_JIT_CALL_CNT = 0;
131     static constexpr uint16_t JIT_DISABLE_FLAG = 0xFFFF;
132     static constexpr size_t JIT_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD = 4;  // 4 : 4 byte offset from bitfield
133     static constexpr size_t JIT_CNT_OFFSET_FROM_THRESHOLD = 2;  // 2 : 2 byte offset from jit hotness threshold
134     static constexpr size_t OSR_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD = 8;  // 8 : 8 byte offset from bitfield
135     static constexpr size_t OSR_CNT_OFFSET_FROM_OSR_THRESHOLD = 2;  // 2 : 2 byte offset from osr hotness threshold
136     static constexpr size_t BASELINEJIT_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD = 12; // 12: bytes offset from bitfield
137     static constexpr size_t JIT_CALL_THRESHOLD_OFFSET_FROM_BITFIELD = 14;  // 12 : 12 byte offset from bitfield
138     // 1 : 1 byte offset from jit call threshold
139     static constexpr size_t JIT_CALL_CNT_OFFSET_FROM_JIT_CALL_THRESHOLD = 1;
140 
Cast(TaggedObject * object)141     static ProfileTypeInfo *Cast(TaggedObject *object)
142     {
143         ASSERT(JSTaggedValue(object).IsTaggedArray());
144         return static_cast<ProfileTypeInfo *>(object);
145     }
146 
ComputeSize(uint32_t icSlotSize)147     static size_t ComputeSize(uint32_t icSlotSize)
148     {
149         return TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), AdjustSlotSize(icSlotSize) + RESERVED_LENGTH);
150     }
151 
GetIcSlotLength()152     inline uint32_t GetIcSlotLength() const
153     {
154         return GetLength() - RESERVED_LENGTH;
155     }
156 
GetIcSlotAndOsrLength()157     inline uint32_t GetIcSlotAndOsrLength() const
158     {
159         return GetLength() - BIT_FIELD_INDEX;
160     }
161 
AdjustSlotSize(uint32_t icSlotSize)162     static inline uint32_t AdjustSlotSize(uint32_t icSlotSize)
163     {
164         // if ic slot size is 0xff comes from frontend, it means the actual size is 0x100.
165         // 0xff is a invalid slot index, which value is hole.
166         if (icSlotSize == INVALID_SLOT_INDEX) {
167             ++icSlotSize;
168         }
169         return icSlotSize;
170     }
171 
SetPrimitiveOfSlot(JSTaggedValue initValue,uint32_t icSlotSize)172     inline void SetPrimitiveOfSlot(JSTaggedValue initValue, uint32_t icSlotSize)
173     {
174         for (uint32_t i = 0; i < icSlotSize; i++) {
175             size_t offset = JSTaggedValue::TaggedTypeSize() * i;
176             if (i == INVALID_SLOT_INDEX) {
177                 Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, JSTaggedValue::Hole().GetRawData());
178             } else {
179                 Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, initValue.GetRawData());
180             }
181         }
182     }
183 
SetSpecialValue()184     inline void SetSpecialValue()
185     {
186         SetPeriodIndex(INITIAL_PERIOD_INDEX);
187         SetJitHotnessThreshold(JIT_DISABLE_FLAG);
188         SetJitHotnessCnt(0);
189         SetBaselineJitHotnessThreshold(JIT_DISABLE_FLAG);
190         SetOsrHotnessThreshold(INITIAL_OSR_HOTNESS_THRESHOLD);
191         SetOsrHotnessCnt(INITIAL_OSR_HOTNESS_CNT);
192         SetJitCallThreshold(INITIAL_JIT_CALL_THRESHOLD);
193         SetJitCallCnt(INITIAL_JIT_CALL_CNT);
194     }
195 
196     inline void InitializeWithSpecialValue(JSTaggedValue initValue, uint32_t icSlotSize, uint32_t extraLength = 0)
197     {
198         ASSERT(initValue.IsSpecial());
199         icSlotSize = AdjustSlotSize(icSlotSize);
200         SetLength(icSlotSize + RESERVED_LENGTH);
201         SetExtraLength(extraLength);
202         SetPrimitiveOfSlot(initValue, icSlotSize);
203         // the last of the cache is used to save osr jit tagged array
204         Barriers::SetPrimitive<JSTaggedType>(
205             GetData(), icSlotSize * JSTaggedValue::TaggedTypeSize(), JSTaggedValue::Undefined().GetRawData());
206         SetSpecialValue();
207     }
208 
SetPreDumpPeriodIndex()209     void SetPreDumpPeriodIndex()
210     {
211         SetPeriodIndex(PRE_DUMP_PERIOD_INDEX);
212     }
213 
IsProfileTypeInfoPreDumped()214     bool IsProfileTypeInfoPreDumped() const
215     {
216         return GetPeriodIndex() == PRE_DUMP_PERIOD_INDEX;
217     }
218 
SetBigMethodPeriodIndex()219     void SetBigMethodPeriodIndex()
220     {
221         SetPeriodIndex(BIG_METHOD_PERIOD_INDEX);
222     }
223 
IsProfileTypeInfoWithBigMethod()224     bool IsProfileTypeInfoWithBigMethod() const
225     {
226         return GetPeriodIndex() == BIG_METHOD_PERIOD_INDEX;
227     }
228 
GetJitHotnessThreshold()229     uint16_t GetJitHotnessThreshold() const
230     {
231         return Barriers::GetValue<uint16_t>(GetData(), GetJitHotnessThresholdBitfieldOffset());
232     }
233 
SetJitHotnessThreshold(uint16_t count)234     void SetJitHotnessThreshold(uint16_t count)
235     {
236         Barriers::SetPrimitive(GetData(), GetJitHotnessThresholdBitfieldOffset(), count);
237     }
238 
GetOsrHotnessThreshold()239     uint16_t GetOsrHotnessThreshold() const
240     {
241         return Barriers::GetValue<uint16_t>(GetData(), GetOsrHotnessThresholdBitfieldOffset());
242     }
243 
SetOsrHotnessThreshold(uint16_t count)244     void SetOsrHotnessThreshold(uint16_t count)
245     {
246         Barriers::SetPrimitive(GetData(), GetOsrHotnessThresholdBitfieldOffset(), count);
247     }
248 
GetBaselineJitHotnessThreshold()249     uint16_t GetBaselineJitHotnessThreshold() const
250     {
251         return Barriers::GetValue<uint16_t>(GetData(), GetBaselineJitHotnessThresholdBitfieldOffset());
252     }
253 
SetBaselineJitHotnessThreshold(uint16_t count)254     void SetBaselineJitHotnessThreshold(uint16_t count)
255     {
256         Barriers::SetPrimitive(GetData(), GetBaselineJitHotnessThresholdBitfieldOffset(), count);
257     }
258 
GetJitCallThreshold()259     uint8_t GetJitCallThreshold() const
260     {
261         return Barriers::GetValue<uint8_t>(GetData(), GetJitCallThresholdBitfieldOffset());
262     }
263 
SetJitCallThreshold(uint8_t count)264     void SetJitCallThreshold(uint8_t count)
265     {
266         Barriers::SetPrimitive(GetData(), GetJitCallThresholdBitfieldOffset(), count);
267     }
268 
GetJitHotnessCnt()269     uint16_t GetJitHotnessCnt() const
270     {
271         return Barriers::GetValue<uint16_t>(GetData(), GetJitHotnessCntBitfieldOffset());
272     }
273 
SetJitHotnessCnt(uint16_t count)274     void SetJitHotnessCnt(uint16_t count)
275     {
276         Barriers::SetPrimitive(GetData(), GetJitHotnessCntBitfieldOffset(), count);
277     }
278 
SetOsrHotnessCnt(uint16_t count)279     void SetOsrHotnessCnt(uint16_t count)
280     {
281         Barriers::SetPrimitive(GetData(), GetOsrHotnessCntBitfieldOffset(), count);
282     }
283 
SetJitCallCnt(uint8_t count)284     void SetJitCallCnt(uint8_t count)
285     {
286         Barriers::SetPrimitive(GetData(), GetJitCallCntBitfieldOffset(), count);
287     }
288 
GetIcSlot(uint32_t idx)289     inline JSTaggedValue GetIcSlot(uint32_t idx) const
290     {
291         ASSERT(idx < GetIcSlotLength());
292         return TaggedArray::Get(idx);
293     }
294 
SetIcSlot(const JSThread * thread,uint32_t idx,const JSTaggedValue & value)295     inline void SetIcSlot(const JSThread* thread, uint32_t idx, const JSTaggedValue& value)
296     {
297         ASSERT(idx < GetIcSlotLength());
298         TaggedArray::Set(thread, idx, value);
299     }
300 
SetMultiIcSlotLocked(JSThread * thread,uint32_t firstIdx,const JSTaggedValue & firstValue,uint32_t secondIdx,const JSTaggedValue & secondValue)301     inline void SetMultiIcSlotLocked(JSThread* thread, uint32_t firstIdx, const JSTaggedValue& firstValue,
302         uint32_t secondIdx, const JSTaggedValue& secondValue)
303     {
304         ProfileTypeAccessorLockScope accessorLockScope(thread);
305         ASSERT(firstIdx < GetIcSlotLength());
306         ASSERT(secondIdx < GetIcSlotLength());
307         TaggedArray::Set(thread, firstIdx, firstValue);
308         TaggedArray::Set(thread, secondIdx, secondValue);
309     }
310 
311     DECL_VISIT_ARRAY(DATA_OFFSET, GetIcSlotAndOsrLength(), GetIcSlotAndOsrLength());
312 
DECL_DUMP()313     DECL_DUMP()
314 
315 private:
316     uint32_t GetPeriodIndex() const
317     {
318         return Barriers::GetValue<uint32_t>(GetData(), GetBitfieldOffset());
319     }
320 
SetPeriodIndex(uint32_t count)321     void SetPeriodIndex(uint32_t count)
322     {
323         Barriers::SetPrimitive(GetData(), GetBitfieldOffset(), count);
324     }
325 
GetBitfieldOffset()326     inline size_t GetBitfieldOffset() const
327     {
328         return JSTaggedValue::TaggedTypeSize() * (GetLength() - BIT_FIELD_INDEX);
329     }
330 
331     // jit hotness(16bits) + count(16bits)
GetJitHotnessThresholdBitfieldOffset()332     inline size_t GetJitHotnessThresholdBitfieldOffset() const
333     {
334         return GetBitfieldOffset() + JIT_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD;
335     }
336 
GetJitHotnessCntBitfieldOffset()337     inline size_t GetJitHotnessCntBitfieldOffset() const
338     {
339         return GetJitHotnessThresholdBitfieldOffset() + JIT_CNT_OFFSET_FROM_THRESHOLD;
340     }
341 
342     // osr hotness(16bits) + count(16bits)
GetOsrHotnessThresholdBitfieldOffset()343     inline size_t GetOsrHotnessThresholdBitfieldOffset() const
344     {
345         return GetBitfieldOffset() + OSR_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD;
346     }
347 
348     // baselinejit hotness(16bits)
GetBaselineJitHotnessThresholdBitfieldOffset()349     inline size_t GetBaselineJitHotnessThresholdBitfieldOffset() const
350     {
351         return GetBitfieldOffset() + BASELINEJIT_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD;
352     }
353 
GetOsrHotnessCntBitfieldOffset()354     inline size_t GetOsrHotnessCntBitfieldOffset() const
355     {
356         return GetOsrHotnessThresholdBitfieldOffset() + OSR_CNT_OFFSET_FROM_OSR_THRESHOLD;
357     }
358 
359     // jit call threshold(8bits) + count(8bits)
GetJitCallThresholdBitfieldOffset()360     inline size_t GetJitCallThresholdBitfieldOffset() const
361     {
362         return GetBitfieldOffset() + JIT_CALL_THRESHOLD_OFFSET_FROM_BITFIELD;
363     }
364 
GetJitCallCntBitfieldOffset()365     inline size_t GetJitCallCntBitfieldOffset() const
366     {
367         return GetJitCallThresholdBitfieldOffset() + JIT_CALL_CNT_OFFSET_FROM_JIT_CALL_THRESHOLD;
368     }
369 };
370 
371 class ProfileTypeAccessor {
372 public:
373     static constexpr size_t CACHE_MAX_LEN = 8;
374     static constexpr size_t MONO_CASE_NUM = 2;
375     static constexpr size_t POLY_CASE_NUM = 4;
376 
377     enum ICState {
378         UNINIT,
379         MONO,
380         POLY,
381         MEGA,
382     };
383 
ProfileTypeAccessor(JSThread * thread,JSHandle<ProfileTypeInfo> profileTypeInfo,uint32_t slotId,ICKind kind)384     ProfileTypeAccessor(JSThread* thread, JSHandle<ProfileTypeInfo> profileTypeInfo, uint32_t slotId, ICKind kind)
385         : thread_(thread), profileTypeInfo_(profileTypeInfo), slotId_(slotId), kind_(kind)
386     {
387     }
388     ~ProfileTypeAccessor() = default;
389 
390     ICState GetICState() const;
391     static std::string ICStateToString(ICState state);
392     void AddHandlerWithoutKey(JSHandle<JSTaggedValue> hclass, JSHandle<JSTaggedValue> handler) const;
393     void AddWithoutKeyPoly(JSHandle<JSTaggedValue> hclass, JSHandle<JSTaggedValue> handler, uint32_t index,
394                            JSTaggedValue profileData) const;
395     void AddElementHandler(JSHandle<JSTaggedValue> hclass, JSHandle<JSTaggedValue> handler) const;
396     void AddHandlerWithKey(JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> hclass,
397                            JSHandle<JSTaggedValue> handler) const;
398     void AddGlobalHandlerKey(JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> handler) const;
399     void AddGlobalRecordHandler(JSHandle<JSTaggedValue> handler) const;
400 
GetWeakRef(JSTaggedValue value)401     JSTaggedValue GetWeakRef(JSTaggedValue value) const
402     {
403         return JSTaggedValue(value.CreateAndGetWeakRef());
404     }
405 
GetRefFromWeak(const JSTaggedValue & value)406     JSTaggedValue GetRefFromWeak(const JSTaggedValue &value) const
407     {
408         return JSTaggedValue(value.GetWeakReferent());
409     }
410     void SetAsMega() const;
411 
GetKind()412     ICKind GetKind() const
413     {
414         return kind_;
415     }
416 
417 private:
418     JSThread* thread_;
419     JSHandle<ProfileTypeInfo> profileTypeInfo_;
420     uint32_t slotId_;
421     ICKind kind_;
422 };
423 }  // namespace panda::ecmascript
424 
425 #endif  // ECMASCRIPT_IC_PROFILE_TYPE_INFO_H
426