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 namespace panda::ecmascript {
AddElementHandler(JSHandle<JSTaggedValue> hclass,JSHandle<JSTaggedValue> handler) const19 void ProfileTypeAccessor::AddElementHandler(JSHandle<JSTaggedValue> hclass, JSHandle<JSTaggedValue> handler) const
20 {
21 ALLOW_LOCAL_TO_SHARE_WEAK_REF_HANDLE;
22 auto profileData = profileTypeInfo_->GetIcSlot(slotId_);
23 ASSERT(!profileData.IsHole());
24 auto index = slotId_;
25 if (profileData.IsUndefined()) {
26 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, GetWeakRef(hclass.GetTaggedValue()),
27 index + 1, handler.GetTaggedValue());
28 return;
29 }
30 // clear key ic
31 if (!profileData.IsWeak() && (profileData.IsString() || profileData.IsSymbol())) {
32 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, GetWeakRef(hclass.GetTaggedValue()),
33 index + 1, handler.GetTaggedValue());
34 return;
35 }
36 AddHandlerWithoutKey(hclass, handler);
37 }
38
AddWithoutKeyPoly(JSHandle<JSTaggedValue> hclass,JSHandle<JSTaggedValue> handler,uint32_t index,JSTaggedValue profileData) const39 void ProfileTypeAccessor::AddWithoutKeyPoly(JSHandle<JSTaggedValue> hclass, JSHandle<JSTaggedValue> handler,
40 uint32_t index, JSTaggedValue profileData) const
41 {
42 ASSERT(profileTypeInfo_->Get(index + 1).IsHole());
43 JSHandle<TaggedArray> arr(thread_, profileData);
44 const uint32_t step = 2;
45 uint32_t newLen = arr->GetLength() + step;
46 if (newLen > CACHE_MAX_LEN) {
47 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, JSTaggedValue::Hole(), index + 1, JSTaggedValue::Hole());
48 return;
49 }
50 auto factory = thread_->GetEcmaVM()->GetFactory();
51 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(newLen);
52 uint32_t i = 0;
53 for (; i < arr->GetLength(); i += step) {
54 newArr->Set(thread_, i, arr->Get(i));
55 newArr->Set(thread_, i + 1, arr->Get(i + 1));
56 }
57 newArr->Set(thread_, i, GetWeakRef(hclass.GetTaggedValue()));
58 newArr->Set(thread_, i + 1, handler.GetTaggedValue());
59 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, newArr.GetTaggedValue(), index + 1, JSTaggedValue::Hole());
60 }
61
AddHandlerWithoutKey(JSHandle<JSTaggedValue> hclass,JSHandle<JSTaggedValue> handler) const62 void ProfileTypeAccessor::AddHandlerWithoutKey(JSHandle<JSTaggedValue> hclass, JSHandle<JSTaggedValue> handler) const
63 {
64 ALLOW_LOCAL_TO_SHARE_WEAK_REF_HANDLE;
65 auto index = slotId_;
66 if (IsNamedGlobalIC(GetKind())) {
67 profileTypeInfo_->SetIcSlot(thread_, index, handler.GetTaggedValue());
68 return;
69 }
70 auto profileData = profileTypeInfo_->GetIcSlot(slotId_);
71 ASSERT(!profileData.IsHole());
72 if (profileData.IsUndefined()) {
73 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, GetWeakRef(hclass.GetTaggedValue()),
74 index + 1, handler.GetTaggedValue());
75 return;
76 }
77 if (!profileData.IsWeak() && profileData.IsTaggedArray()) { // POLY
78 AddWithoutKeyPoly(hclass, handler, index, profileData);
79 return;
80 }
81 // MONO to POLY
82 auto factory = thread_->GetEcmaVM()->GetFactory();
83 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(POLY_CASE_NUM);
84 uint32_t arrIndex = 0;
85 newArr->Set(thread_, arrIndex++, profileTypeInfo_->GetIcSlot(index));
86 newArr->Set(thread_, arrIndex++, profileTypeInfo_->GetIcSlot(index + 1));
87 newArr->Set(thread_, arrIndex++, GetWeakRef(hclass.GetTaggedValue()));
88 newArr->Set(thread_, arrIndex, handler.GetTaggedValue());
89
90 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, newArr.GetTaggedValue(), index + 1, JSTaggedValue::Hole());
91 }
92
AddHandlerWithKey(JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> hclass,JSHandle<JSTaggedValue> handler) const93 void ProfileTypeAccessor::AddHandlerWithKey(JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> hclass,
94 JSHandle<JSTaggedValue> handler) const
95 {
96 ALLOW_LOCAL_TO_SHARE_WEAK_REF_HANDLE;
97 if (IsValueGlobalIC(GetKind())) {
98 AddGlobalHandlerKey(key, handler);
99 return;
100 }
101 auto profileData = profileTypeInfo_->GetIcSlot(slotId_);
102 ASSERT(!profileData.IsHole());
103 auto index = slotId_;
104 if (profileData.IsUndefined()) {
105 const int arrayLength = 2;
106 JSHandle<TaggedArray> newArr = thread_->GetEcmaVM()->GetFactory()->NewTaggedArray(arrayLength);
107 newArr->Set(thread_, 0, GetWeakRef(hclass.GetTaggedValue()));
108 newArr->Set(thread_, 1, handler.GetTaggedValue());
109 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index,
110 key.GetTaggedValue(), index + 1, newArr.GetTaggedValue());
111 return;
112 }
113 // for element ic, profileData may hclass or tagged array
114 if (key.GetTaggedValue() != profileData) {
115 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index, JSTaggedValue::Hole(), index + 1, JSTaggedValue::Hole());
116 return;
117 }
118 JSTaggedValue patchValue = profileTypeInfo_->GetIcSlot(index + 1);
119 ASSERT(patchValue.IsTaggedArray());
120 JSHandle<TaggedArray> arr(thread_, patchValue);
121 const uint32_t step = 2;
122 if (arr->GetLength() > step) { // POLY
123 uint32_t newLen = arr->GetLength() + step;
124 if (newLen > CACHE_MAX_LEN) {
125 profileTypeInfo_->SetMultiIcSlotLocked(thread_, index,
126 JSTaggedValue::Hole(), index + 1, JSTaggedValue::Hole());
127 return;
128 }
129 auto factory = thread_->GetEcmaVM()->GetFactory();
130 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(newLen);
131 newArr->Set(thread_, 0, GetWeakRef(hclass.GetTaggedValue()));
132 newArr->Set(thread_, 1, handler.GetTaggedValue());
133 for (uint32_t i = 0; i < arr->GetLength(); i += step) {
134 newArr->Set(thread_, i + step, arr->Get(i));
135 newArr->Set(thread_, i + step + 1, arr->Get(i + 1));
136 }
137 profileTypeInfo_->SetIcSlot(thread_, index + 1, newArr.GetTaggedValue());
138 return;
139 }
140 // MONO
141 auto factory = thread_->GetEcmaVM()->GetFactory();
142 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(POLY_CASE_NUM);
143 uint32_t arrIndex = 0;
144 newArr->Set(thread_, arrIndex++, arr->Get(0));
145 newArr->Set(thread_, arrIndex++, arr->Get(1));
146 newArr->Set(thread_, arrIndex++, GetWeakRef(hclass.GetTaggedValue()));
147 newArr->Set(thread_, arrIndex++, handler.GetTaggedValue());
148
149 profileTypeInfo_->SetIcSlot(thread_, index + 1, newArr.GetTaggedValue());
150 }
151
AddGlobalHandlerKey(JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> handler) const152 void ProfileTypeAccessor::AddGlobalHandlerKey(JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> handler) const
153 {
154 ALLOW_LOCAL_TO_SHARE_WEAK_REF_HANDLE;
155 auto index = slotId_;
156 const uint8_t step = 2; // key and value pair
157 JSTaggedValue indexVal = profileTypeInfo_->GetIcSlot(index);
158 if (indexVal.IsUndefined()) {
159 auto factory = thread_->GetEcmaVM()->GetFactory();
160 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(step);
161 newArr->Set(thread_, 0, GetWeakRef(key.GetTaggedValue()));
162 newArr->Set(thread_, 1, handler.GetTaggedValue());
163 profileTypeInfo_->SetIcSlot(thread_, index, newArr.GetTaggedValue());
164 return;
165 }
166 ASSERT(indexVal.IsTaggedArray());
167 JSHandle<TaggedArray> arr(thread_, indexVal);
168 uint32_t newLen = arr->GetLength() + step;
169 if (newLen > CACHE_MAX_LEN) {
170 profileTypeInfo_->SetIcSlot(thread_, index, JSTaggedValue::Hole());
171 return;
172 }
173 auto factory = thread_->GetEcmaVM()->GetFactory();
174 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(newLen);
175 newArr->Set(thread_, 0, GetWeakRef(key.GetTaggedValue()));
176 newArr->Set(thread_, 1, handler.GetTaggedValue());
177
178 for (uint32_t i = 0; i < arr->GetLength(); i += step) {
179 newArr->Set(thread_, i + step, arr->Get(i));
180 newArr->Set(thread_, i + step + 1, arr->Get(i + 1));
181 }
182 profileTypeInfo_->SetIcSlot(thread_, index, newArr.GetTaggedValue());
183 }
184
AddGlobalRecordHandler(JSHandle<JSTaggedValue> handler) const185 void ProfileTypeAccessor::AddGlobalRecordHandler(JSHandle<JSTaggedValue> handler) const
186 {
187 uint32_t index = slotId_;
188 profileTypeInfo_->SetIcSlot(thread_, index, handler.GetTaggedValue());
189 }
190
SetAsMega() const191 void ProfileTypeAccessor::SetAsMega() const
192 {
193 if (IsGlobalIC(kind_)) {
194 profileTypeInfo_->SetIcSlot(thread_, slotId_, JSTaggedValue::Hole());
195 } else {
196 profileTypeInfo_->SetMultiIcSlotLocked(thread_, slotId_,
197 JSTaggedValue::Hole(), slotId_ + 1, JSTaggedValue::Hole());
198 }
199 }
200
ICKindToString(ICKind kind)201 std::string ICKindToString(ICKind kind)
202 {
203 switch (kind) {
204 case ICKind::NamedLoadIC:
205 return "NamedLoadIC";
206 case ICKind::NamedStoreIC:
207 return "NamedStoreIC";
208 case ICKind::LoadIC:
209 return "LoadIC";
210 case ICKind::StoreIC:
211 return "StoreIC";
212 case ICKind::NamedGlobalLoadIC:
213 return "NamedGlobalLoadIC";
214 case ICKind::NamedGlobalStoreIC:
215 return "NamedGlobalStoreIC";
216 case ICKind::NamedGlobalTryLoadIC:
217 return "NamedGlobalTryLoadIC";
218 case ICKind::NamedGlobalTryStoreIC:
219 return "NamedGlobalTryStoreIC";
220 case ICKind::GlobalLoadIC:
221 return "GlobalLoadIC";
222 case ICKind::GlobalStoreIC:
223 return "GlobalStoreIC";
224 default:
225 LOG_ECMA(FATAL) << "this branch is unreachable";
226 UNREACHABLE();
227 break;
228 }
229 }
230
ICStateToString(ProfileTypeAccessor::ICState state)231 std::string ProfileTypeAccessor::ICStateToString(ProfileTypeAccessor::ICState state)
232 {
233 switch (state) {
234 case ICState::UNINIT:
235 return "uninit";
236 case ICState::MONO:
237 return "mono";
238 case ICState::POLY:
239 return "poly";
240 case ICState::MEGA:
241 return "mega";
242 default:
243 LOG_ECMA(FATAL) << "this branch is unreachable";
244 UNREACHABLE();
245 break;
246 }
247 }
248
GetICState() const249 ProfileTypeAccessor::ICState ProfileTypeAccessor::GetICState() const
250 {
251 auto profileData = profileTypeInfo_->GetIcSlot(slotId_);
252 if (profileData.IsUndefined()) {
253 return ICState::UNINIT;
254 }
255
256 if (profileData.IsHole()) {
257 return ICState::MEGA;
258 }
259
260 switch (kind_) {
261 case ICKind::NamedLoadIC:
262 case ICKind::NamedStoreIC:
263 if (profileData.IsWeak()) {
264 return ICState::MONO;
265 }
266 ASSERT(profileData.IsTaggedArray());
267 return ICState::POLY;
268 case ICKind::LoadIC:
269 case ICKind::StoreIC: {
270 if (profileData.IsWeak()) {
271 return ICState::MONO;
272 }
273 if (profileData.IsTaggedArray()) {
274 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
275 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
276 }
277 profileData = profileTypeInfo_->GetIcSlot(slotId_ + 1);
278 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
279 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
280 }
281 case ICKind::NamedGlobalLoadIC:
282 case ICKind::NamedGlobalStoreIC:
283 case ICKind::NamedGlobalTryLoadIC:
284 case ICKind::NamedGlobalTryStoreIC:
285 ASSERT(profileData.IsPropertyBox());
286 return ICState::MONO;
287 case ICKind::GlobalLoadIC:
288 case ICKind::GlobalStoreIC: {
289 ASSERT(profileData.IsTaggedArray());
290 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
291 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
292 }
293 default:
294 LOG_ECMA(FATAL) << "this branch is unreachable";
295 UNREACHABLE();
296 break;
297 }
298 return ICState::UNINIT;
299 }
300 } // namespace panda::ecmascript
301