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