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 #include "ecmascript/ic/profile_type_info.h"
17
18 #include "ecmascript/ic/ic_handler.h"
19 #include "ecmascript/js_function.h"
20 #include "ecmascript/js_tagged_value.h"
21 #include "ecmascript/tagged_array-inl.h"
22 #include "macros.h"
23
24 namespace panda::ecmascript {
AddElementHandler(JSHandle<JSTaggedValue> hclass,JSHandle<JSTaggedValue> handler) const25 void ProfileTypeAccessor::AddElementHandler(JSHandle<JSTaggedValue> hclass, JSHandle<JSTaggedValue> handler) const
26 {
27 ALLOW_LOCAL_TO_SHARE_WEAK_REF_HANDLE;
28 auto profileData = profileTypeInfo_->GetIcSlot(slotId_);
29 ASSERT(!profileData.IsHole());
30 auto index = slotId_;
31 if (profileData.IsUndefined()) {
32 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, GetWeakRef(hclass.GetTaggedValue()),
33 index + 1, handler.GetTaggedValue());
34 return;
35 }
36 // clear key ic
37 if (!profileData.IsWeak() && (profileData.IsString() || profileData.IsSymbol())) {
38 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, GetWeakRef(hclass.GetTaggedValue()),
39 index + 1, handler.GetTaggedValue());
40 return;
41 }
42 AddHandlerWithoutKey(hclass, handler);
43 }
44
AddWithoutKeyPoly(JSHandle<JSTaggedValue> hclass,JSHandle<JSTaggedValue> handler,uint32_t index,JSTaggedValue profileData,JSHandle<JSTaggedValue> keyForMegaIC,MegaICCache::MegaICKind kind) const45 void ProfileTypeAccessor::AddWithoutKeyPoly(JSHandle<JSTaggedValue> hclass, JSHandle<JSTaggedValue> handler,
46 uint32_t index, JSTaggedValue profileData,
47 JSHandle<JSTaggedValue> keyForMegaIC, MegaICCache::MegaICKind kind) const
48 {
49 ASSERT(profileTypeInfo_->GetIcSlot(index + 1).IsHole());
50 JSHandle<TaggedArray> arr(thread_, profileData);
51 const uint32_t step = 2;
52 uint32_t newLen = arr->GetLength() + step;
53 if (newLen > CACHE_MAX_LEN) {
54 if (!enableICMega_ || keyForMegaIC.IsEmpty() || !keyForMegaIC->IsString()) {
55 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, JSTaggedValue::Hole(), index + 1,
56 JSTaggedValue::Hole());
57 return;
58 }
59 // The keyForMegaIC must be a String to ensure fast subsequent reads; assembly code will access using
60 // String.
61 ASSERT(keyForMegaIC->IsString());
62 ASSERT(kind != MegaICCache::None);
63 MegaICCache *cache = nullptr;
64 if (kind == MegaICCache::Load) {
65 cache = thread_->GetLoadMegaICCache();
66 } else {
67 cache = thread_->GetStoreMegaICCache();
68 }
69
70 uint32_t i = 0;
71 for (; i < arr->GetLength(); i += step) {
72 if (arr->Get(i) == JSTaggedValue::Undefined()) {
73 continue;
74 }
75 cache->Set(JSHClass::Cast(arr->Get(i).GetWeakReferentUnChecked()), keyForMegaIC.GetTaggedValue(),
76 arr->Get(i + 1), thread_);
77 }
78 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, JSTaggedValue::Hole(), index + 1,
79 keyForMegaIC.GetTaggedValue());
80 return;
81 }
82
83 auto factory = thread_->GetEcmaVM()->GetFactory();
84 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(newLen);
85 uint32_t i = 0;
86 for (; i < arr->GetLength(); i += step) {
87 newArr->Set(thread_, i, arr->Get(i));
88 newArr->Set(thread_, i + 1, arr->Get(i + 1));
89 }
90 newArr->Set(thread_, i, GetWeakRef(hclass.GetTaggedValue()));
91 newArr->Set(thread_, i + 1, handler.GetTaggedValue());
92 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, newArr.GetTaggedValue(), index + 1, JSTaggedValue::Hole());
93 }
94
AddHandlerWithoutKey(JSHandle<JSTaggedValue> hclass,JSHandle<JSTaggedValue> handler,JSHandle<JSTaggedValue> keyForMegaIC,MegaICCache::MegaICKind kind) const95 void ProfileTypeAccessor::AddHandlerWithoutKey(JSHandle<JSTaggedValue> hclass, JSHandle<JSTaggedValue> handler,
96 JSHandle<JSTaggedValue> keyForMegaIC,
97 MegaICCache::MegaICKind kind) const
98 {
99 ALLOW_LOCAL_TO_SHARE_WEAK_REF_HANDLE;
100 auto index = slotId_;
101 if (IsNamedGlobalIC(GetKind())) {
102 profileTypeInfo_->SetIcSlot(thread_, index, handler.GetTaggedValue());
103 return;
104 }
105 auto profileData = profileTypeInfo_->GetIcSlot(slotId_);
106 ASSERT(!profileData.IsHole());
107 if (profileData.IsUndefined()) {
108 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, GetWeakRef(hclass.GetTaggedValue()),
109 index + 1, handler.GetTaggedValue());
110 return;
111 }
112 if (!profileData.IsWeak() && profileData.IsTaggedArray()) { // POLY
113 AddWithoutKeyPoly(hclass, handler, index, profileData, keyForMegaIC, kind);
114 return;
115 }
116 // MONO to POLY
117 auto factory = thread_->GetEcmaVM()->GetFactory();
118 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(POLY_CASE_NUM);
119 uint32_t arrIndex = 0;
120 newArr->Set(thread_, arrIndex++, profileTypeInfo_->GetIcSlot(index));
121 newArr->Set(thread_, arrIndex++, profileTypeInfo_->GetIcSlot(index + 1));
122 newArr->Set(thread_, arrIndex++, GetWeakRef(hclass.GetTaggedValue()));
123 newArr->Set(thread_, arrIndex, handler.GetTaggedValue());
124
125 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, newArr.GetTaggedValue(), index + 1, JSTaggedValue::Hole());
126 }
127
AddHandlerWithKey(JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> hclass,JSHandle<JSTaggedValue> handler) const128 void ProfileTypeAccessor::AddHandlerWithKey(JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> hclass,
129 JSHandle<JSTaggedValue> handler) const
130 {
131 ALLOW_LOCAL_TO_SHARE_WEAK_REF_HANDLE;
132 if (IsValueGlobalIC(GetKind())) {
133 AddGlobalHandlerKey(key, handler);
134 return;
135 }
136 auto profileData = profileTypeInfo_->GetIcSlot(slotId_);
137 ASSERT(!profileData.IsHole());
138 auto index = slotId_;
139 if (profileData.IsUndefined()) {
140 const int arrayLength = 2;
141 JSHandle<TaggedArray> newArr = thread_->GetEcmaVM()->GetFactory()->NewTaggedArray(arrayLength);
142 newArr->Set(thread_, 0, GetWeakRef(hclass.GetTaggedValue()));
143 newArr->Set(thread_, 1, handler.GetTaggedValue());
144 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index,
145 key.GetTaggedValue(), index + 1, newArr.GetTaggedValue());
146 return;
147 }
148 // for element ic, profileData may hclass or tagged array
149 if (key.GetTaggedValue() != profileData) {
150 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, JSTaggedValue::Hole(), index + 1, JSTaggedValue::Hole());
151 return;
152 }
153 JSTaggedValue patchValue = profileTypeInfo_->GetIcSlot(index + 1);
154 ASSERT(patchValue.IsTaggedArray());
155 JSHandle<TaggedArray> arr(thread_, patchValue);
156 const uint32_t step = 2;
157 if (arr->GetLength() > step) { // POLY
158 uint32_t newLen = arr->GetLength() + step;
159 if (newLen > CACHE_MAX_LEN) {
160 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index,
161 JSTaggedValue::Hole(), index + 1, JSTaggedValue::Hole());
162 return;
163 }
164 auto factory = thread_->GetEcmaVM()->GetFactory();
165 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(newLen);
166 newArr->Set(thread_, 0, GetWeakRef(hclass.GetTaggedValue()));
167 newArr->Set(thread_, 1, handler.GetTaggedValue());
168 for (uint32_t i = 0; i < arr->GetLength(); i += step) {
169 newArr->Set(thread_, i + step, arr->Get(i));
170 newArr->Set(thread_, i + step + 1, arr->Get(i + 1));
171 }
172 profileTypeInfo_->SetIcSlot(thread_, index + 1, newArr.GetTaggedValue());
173 return;
174 }
175 // MONO
176 auto factory = thread_->GetEcmaVM()->GetFactory();
177 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(POLY_CASE_NUM);
178 uint32_t arrIndex = 0;
179 newArr->Set(thread_, arrIndex++, arr->Get(0));
180 newArr->Set(thread_, arrIndex++, arr->Get(1));
181 newArr->Set(thread_, arrIndex++, GetWeakRef(hclass.GetTaggedValue()));
182 newArr->Set(thread_, arrIndex++, handler.GetTaggedValue());
183
184 profileTypeInfo_->SetIcSlot(thread_, index + 1, newArr.GetTaggedValue());
185 }
186
AddGlobalHandlerKey(JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> handler) const187 void ProfileTypeAccessor::AddGlobalHandlerKey(JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> handler) const
188 {
189 ALLOW_LOCAL_TO_SHARE_WEAK_REF_HANDLE;
190 auto index = slotId_;
191 const uint8_t step = 2; // key and value pair
192 JSTaggedValue indexVal = profileTypeInfo_->GetIcSlot(index);
193 if (indexVal.IsUndefined()) {
194 auto factory = thread_->GetEcmaVM()->GetFactory();
195 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(step);
196 newArr->Set(thread_, 0, GetWeakRef(key.GetTaggedValue()));
197 newArr->Set(thread_, 1, handler.GetTaggedValue());
198 profileTypeInfo_->SetIcSlot(thread_, index, newArr.GetTaggedValue());
199 return;
200 }
201 ASSERT(indexVal.IsTaggedArray());
202 JSHandle<TaggedArray> arr(thread_, indexVal);
203 uint32_t newLen = arr->GetLength() + step;
204 if (newLen > CACHE_MAX_LEN) {
205 profileTypeInfo_->SetIcSlot(thread_, index, JSTaggedValue::Hole());
206 return;
207 }
208 auto factory = thread_->GetEcmaVM()->GetFactory();
209 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(newLen);
210 newArr->Set(thread_, 0, GetWeakRef(key.GetTaggedValue()));
211 newArr->Set(thread_, 1, handler.GetTaggedValue());
212
213 for (uint32_t i = 0; i < arr->GetLength(); i += step) {
214 newArr->Set(thread_, i + step, arr->Get(i));
215 newArr->Set(thread_, i + step + 1, arr->Get(i + 1));
216 }
217 profileTypeInfo_->SetIcSlot(thread_, index, newArr.GetTaggedValue());
218 }
219
AddGlobalRecordHandler(JSHandle<JSTaggedValue> handler) const220 void ProfileTypeAccessor::AddGlobalRecordHandler(JSHandle<JSTaggedValue> handler) const
221 {
222 uint32_t index = slotId_;
223 profileTypeInfo_->SetIcSlot(thread_, index, handler.GetTaggedValue());
224 }
SetAsMegaForTraceSlowMode(ObjectOperator & op) const225 void ProfileTypeAccessor::SetAsMegaForTraceSlowMode([[maybe_unused]] ObjectOperator& op) const
226 {
227 #if ECMASCRIPT_ENABLE_TRACE_LOAD
228 if (op.IsFoundDict()) {
229 SetAsMegaForTrace(JSTaggedValue(ProfileTypeAccessor::MegaState::DICT_MEGA));
230 } else if (!op.IsFound()) {
231 SetAsMegaForTrace(JSTaggedValue(ProfileTypeAccessor::MegaState::NOTFOUND_MEGA));
232 } else {
233 SetAsMega();
234 }
235 #else
236 SetAsMega();
237 #endif
238 }
SetAsMega() const239 void ProfileTypeAccessor::SetAsMega() const
240 {
241 if (IsGlobalIC(kind_)) {
242 profileTypeInfo_->SetIcSlot(thread_, slotId_, JSTaggedValue::Hole());
243 } else {
244 profileTypeInfo_->SetMultiIcSlotLocked(thread_, slotId_,
245 JSTaggedValue::Hole(), slotId_ + 1, JSTaggedValue::Hole());
246 }
247 }
248
SetAsMegaForTrace(JSTaggedValue value) const249 void ProfileTypeAccessor::SetAsMegaForTrace(JSTaggedValue value) const
250 {
251 if (IsGlobalIC(kind_)) {
252 profileTypeInfo_->SetIcSlot(thread_, slotId_, JSTaggedValue::Hole());
253 } else {
254 profileTypeInfo_->SetMultiIcSlotLocked(thread_, slotId_,
255 JSTaggedValue::Hole(), slotId_ + 1, value);
256 }
257 }
258
ICKindToString(ICKind kind)259 std::string ICKindToString(ICKind kind)
260 {
261 switch (kind) {
262 case ICKind::NamedLoadIC:
263 return "NamedLoadIC";
264 case ICKind::NamedStoreIC:
265 return "NamedStoreIC";
266 case ICKind::LoadIC:
267 return "LoadIC";
268 case ICKind::StoreIC:
269 return "StoreIC";
270 case ICKind::NamedGlobalLoadIC:
271 return "NamedGlobalLoadIC";
272 case ICKind::NamedGlobalStoreIC:
273 return "NamedGlobalStoreIC";
274 case ICKind::NamedGlobalTryLoadIC:
275 return "NamedGlobalTryLoadIC";
276 case ICKind::NamedGlobalTryStoreIC:
277 return "NamedGlobalTryStoreIC";
278 case ICKind::GlobalLoadIC:
279 return "GlobalLoadIC";
280 case ICKind::GlobalStoreIC:
281 return "GlobalStoreIC";
282 default:
283 LOG_ECMA(FATAL) << "this branch is unreachable";
284 UNREACHABLE();
285 break;
286 }
287 }
288
ICStateToString(ProfileTypeAccessor::ICState state)289 std::string ProfileTypeAccessor::ICStateToString(ProfileTypeAccessor::ICState state)
290 {
291 switch (state) {
292 case ICState::UNINIT:
293 return "uninit";
294 case ICState::MONO:
295 return "mono";
296 case ICState::POLY:
297 return "poly";
298 case ICState::MEGA:
299 return "mega";
300 case ICState::IC_MEGA:
301 return "ic_mega";
302 default:
303 LOG_ECMA(FATAL) << "this branch is unreachable";
304 UNREACHABLE();
305 break;
306 }
307 }
GetMegaState() const308 ProfileTypeAccessor::ICState ProfileTypeAccessor::GetMegaState() const
309 {
310 auto profileDataSecond = profileTypeInfo_->Get(slotId_ + 1);
311 if (profileDataSecond.IsString()) {
312 return ICState::IC_MEGA;
313 } else {
314 return ICState::MEGA;
315 }
316 }
317
GetICState() const318 ProfileTypeAccessor::ICState ProfileTypeAccessor::GetICState() const
319 {
320 auto profileData = profileTypeInfo_->GetIcSlot(slotId_);
321 if (profileData.IsUndefined()) {
322 return ICState::UNINIT;
323 }
324
325 if (profileData.IsHole()) {
326 return GetMegaState();
327 }
328
329 switch (kind_) {
330 case ICKind::NamedLoadIC:
331 case ICKind::NamedStoreIC:
332 if (profileData.IsWeak()) {
333 return ICState::MONO;
334 }
335 ASSERT(profileData.IsTaggedArray());
336 return ICState::POLY;
337 case ICKind::LoadIC:
338 case ICKind::StoreIC: {
339 if (profileData.IsWeak()) {
340 return ICState::MONO;
341 }
342 if (profileData.IsTaggedArray()) {
343 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
344 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
345 }
346 profileData = profileTypeInfo_->GetIcSlot(slotId_ + 1);
347 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
348 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
349 }
350 case ICKind::NamedGlobalLoadIC:
351 case ICKind::NamedGlobalStoreIC:
352 case ICKind::NamedGlobalTryLoadIC:
353 case ICKind::NamedGlobalTryStoreIC:
354 ASSERT(profileData.IsPropertyBox());
355 return ICState::MONO;
356 case ICKind::GlobalLoadIC:
357 case ICKind::GlobalStoreIC: {
358 ASSERT(profileData.IsTaggedArray());
359 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
360 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
361 }
362 default:
363 LOG_ECMA(FATAL) << "this branch is unreachable";
364 UNREACHABLE();
365 break;
366 }
367 return ICState::UNINIT;
368 }
369 } // namespace panda::ecmascript
370