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/tagged_array-inl.h"
21
22 namespace panda::ecmascript {
AddElementHandler(JSHandle<JSTaggedValue> hclass,JSHandle<JSTaggedValue> handler) const23 void ProfileTypeAccessor::AddElementHandler(JSHandle<JSTaggedValue> hclass, JSHandle<JSTaggedValue> handler) const
24 {
25 auto profileData = profileTypeInfo_->Get(slotId_);
26 ASSERT(!profileData.IsHole());
27 auto index = slotId_;
28 if (profileData.IsUndefined()) {
29 profileTypeInfo_->Set(thread_, index, GetWeakRef(hclass.GetTaggedValue()));
30 profileTypeInfo_->Set(thread_, index + 1, handler.GetTaggedValue());
31 return;
32 }
33 // clear key ic
34 if (!profileData.IsWeak() && (profileData.IsString() || profileData.IsSymbol())) {
35 profileTypeInfo_->Set(thread_, index, GetWeakRef(hclass.GetTaggedValue()));
36 profileTypeInfo_->Set(thread_, index + 1, handler.GetTaggedValue());
37 return;
38 }
39 AddHandlerWithoutKey(hclass, handler);
40 }
41
AddHandlerWithoutKey(JSHandle<JSTaggedValue> hclass,JSHandle<JSTaggedValue> handler) const42 void ProfileTypeAccessor::AddHandlerWithoutKey(JSHandle<JSTaggedValue> hclass, JSHandle<JSTaggedValue> handler) const
43 {
44 auto index = slotId_;
45 if (IsNamedGlobalIC(GetKind())) {
46 profileTypeInfo_->Set(thread_, index, handler.GetTaggedValue());
47 return;
48 }
49 auto profileData = profileTypeInfo_->Get(slotId_);
50 ASSERT(!profileData.IsHole());
51 if (profileData.IsUndefined()) {
52 profileTypeInfo_->Set(thread_, index, GetWeakRef(hclass.GetTaggedValue()));
53 profileTypeInfo_->Set(thread_, index + 1, handler.GetTaggedValue());
54 return;
55 }
56 if (!profileData.IsWeak() && profileData.IsTaggedArray()) { // POLY
57 ASSERT(profileTypeInfo_->Get(index + 1) == JSTaggedValue::Hole());
58 JSHandle<TaggedArray> arr(thread_, profileData);
59 const uint32_t step = 2;
60 uint32_t newLen = arr->GetLength() + step;
61 if (newLen > CACHE_MAX_LEN) {
62 profileTypeInfo_->Set(thread_, index, JSTaggedValue::Hole());
63 profileTypeInfo_->Set(thread_, index + 1, JSTaggedValue::Hole());
64 return;
65 }
66 auto factory = thread_->GetEcmaVM()->GetFactory();
67 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(newLen);
68 uint32_t i = 0;
69 for (; i < arr->GetLength(); i += step) {
70 newArr->Set(thread_, i, arr->Get(i));
71 newArr->Set(thread_, i + 1, arr->Get(i + 1));
72 }
73 newArr->Set(thread_, i, GetWeakRef(hclass.GetTaggedValue()));
74 newArr->Set(thread_, i + 1, handler.GetTaggedValue());
75 profileTypeInfo_->Set(thread_, index, newArr.GetTaggedValue());
76 profileTypeInfo_->Set(thread_, index + 1, JSTaggedValue::Hole());
77 return;
78 }
79 // MONO to POLY
80 auto factory = thread_->GetEcmaVM()->GetFactory();
81 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(POLY_CASE_NUM);
82 uint32_t arrIndex = 0;
83 newArr->Set(thread_, arrIndex++, profileTypeInfo_->Get(index));
84 newArr->Set(thread_, arrIndex++, profileTypeInfo_->Get(index + 1));
85 newArr->Set(thread_, arrIndex++, GetWeakRef(hclass.GetTaggedValue()));
86 newArr->Set(thread_, arrIndex, handler.GetTaggedValue());
87
88 profileTypeInfo_->Set(thread_, index, newArr.GetTaggedValue());
89 profileTypeInfo_->Set(thread_, index + 1, JSTaggedValue::Hole());
90 }
91
AddHandlerWithKey(JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> hclass,JSHandle<JSTaggedValue> handler) const92 void ProfileTypeAccessor::AddHandlerWithKey(JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> hclass,
93 JSHandle<JSTaggedValue> handler) const
94 {
95 if (IsValueGlobalIC(GetKind())) {
96 AddGlobalHandlerKey(key, handler);
97 return;
98 }
99 auto profileData = profileTypeInfo_->Get(slotId_);
100 ASSERT(!profileData.IsHole());
101 auto index = slotId_;
102 if (profileData.IsUndefined()) {
103 ASSERT(profileTypeInfo_->Get(index + 1) == JSTaggedValue::Undefined());
104 profileTypeInfo_->Set(thread_, index, key.GetTaggedValue());
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_->Set(thread_, index + 1, newArr.GetTaggedValue());
110 return;
111 }
112 // for element ic, profileData may hclass or taggedarray
113 if (key.GetTaggedValue() != profileData) {
114 profileTypeInfo_->Set(thread_, index, JSTaggedValue::Hole());
115 profileTypeInfo_->Set(thread_, index + 1, JSTaggedValue::Hole());
116 return;
117 }
118 JSTaggedValue patchValue = profileTypeInfo_->Get(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_->Set(thread_, index, JSTaggedValue::Hole());
126 profileTypeInfo_->Set(thread_, 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_->Set(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_->Set(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 auto index = slotId_;
155 const uint8_t step = 2; // key and value pair
156 JSTaggedValue indexVal = profileTypeInfo_->Get(index);
157 if (indexVal.IsUndefined()) {
158 auto factory = thread_->GetEcmaVM()->GetFactory();
159 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(step);
160 newArr->Set(thread_, 0, GetWeakRef(key.GetTaggedValue()));
161 newArr->Set(thread_, 1, handler.GetTaggedValue());
162 profileTypeInfo_->Set(thread_, index, newArr.GetTaggedValue());
163 return;
164 }
165 ASSERT(indexVal.IsTaggedArray());
166 JSHandle<TaggedArray> arr(thread_, indexVal);
167 uint32_t newLen = arr->GetLength() + step;
168 if (newLen > CACHE_MAX_LEN) {
169 profileTypeInfo_->Set(thread_, index, JSTaggedValue::Hole());
170 return;
171 }
172 auto factory = thread_->GetEcmaVM()->GetFactory();
173 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(newLen);
174 newArr->Set(thread_, 0, GetWeakRef(key.GetTaggedValue()));
175 newArr->Set(thread_, 1, handler.GetTaggedValue());
176
177 for (uint32_t i = 0; i < arr->GetLength(); i += step) {
178 newArr->Set(thread_, i + step, arr->Get(i));
179 newArr->Set(thread_, i + step + 1, arr->Get(i + 1));
180 }
181 profileTypeInfo_->Set(thread_, index, newArr.GetTaggedValue());
182 }
183
AddGlobalRecordHandler(JSHandle<JSTaggedValue> handler) const184 void ProfileTypeAccessor::AddGlobalRecordHandler(JSHandle<JSTaggedValue> handler) const
185 {
186 uint32_t index = slotId_;
187 profileTypeInfo_->Set(thread_, index, handler.GetTaggedValue());
188 }
189
SetAsMega() const190 void ProfileTypeAccessor::SetAsMega() const
191 {
192 profileTypeInfo_->Set(thread_, slotId_, JSTaggedValue::Hole());
193 profileTypeInfo_->Set(thread_, slotId_ + 1, JSTaggedValue::Hole());
194 }
195
ICKindToString(ICKind kind)196 std::string ICKindToString(ICKind kind)
197 {
198 switch (kind) {
199 case ICKind::NamedLoadIC:
200 return "NamedLoadIC";
201 case ICKind::NamedStoreIC:
202 return "NamedStoreIC";
203 case ICKind::LoadIC:
204 return "LoadIC";
205 case ICKind::StoreIC:
206 return "StoreIC";
207 case ICKind::NamedGlobalLoadIC:
208 return "NamedGlobalLoadIC";
209 case ICKind::NamedGlobalStoreIC:
210 return "NamedGlobalStoreIC";
211 case ICKind::NamedGlobalTryLoadIC:
212 return "NamedGlobalTryLoadIC";
213 case ICKind::NamedGlobalTryStoreIC:
214 return "NamedGlobalTryStoreIC";
215 case ICKind::GlobalLoadIC:
216 return "GlobalLoadIC";
217 case ICKind::GlobalStoreIC:
218 return "GlobalStoreIC";
219 default:
220 UNREACHABLE();
221 break;
222 }
223 }
224
ICStateToString(ProfileTypeAccessor::ICState state)225 std::string ProfileTypeAccessor::ICStateToString(ProfileTypeAccessor::ICState state)
226 {
227 switch (state) {
228 case ICState::UNINIT:
229 return "uninit";
230 case ICState::MONO:
231 return "mono";
232 case ICState::POLY:
233 return "poly";
234 case ICState::MEGA:
235 return "mega";
236 default:
237 UNREACHABLE();
238 break;
239 }
240 }
241
GetICState() const242 ProfileTypeAccessor::ICState ProfileTypeAccessor::GetICState() const
243 {
244 auto profileData = profileTypeInfo_->Get(slotId_);
245 if (profileData.IsUndefined()) {
246 return ICState::UNINIT;
247 }
248
249 if (profileData.IsHole()) {
250 return ICState::MEGA;
251 }
252
253 switch (kind_) {
254 case ICKind::NamedLoadIC:
255 case ICKind::NamedStoreIC:
256 if (profileData.IsWeak()) {
257 return ICState::MONO;
258 }
259 ASSERT(profileData.IsTaggedArray());
260 return ICState::POLY;
261 case ICKind::LoadIC:
262 case ICKind::StoreIC: {
263 if (profileData.IsWeak()) {
264 return ICState::MONO;
265 }
266 if (profileData.IsTaggedArray()) {
267 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
268 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
269 }
270 profileData = profileTypeInfo_->Get(slotId_ + 1);
271 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
272 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
273 }
274 case ICKind::NamedGlobalLoadIC:
275 case ICKind::NamedGlobalStoreIC:
276 case ICKind::NamedGlobalTryLoadIC:
277 case ICKind::NamedGlobalTryStoreIC:
278 ASSERT(profileData.IsPropertyBox());
279 return ICState::MONO;
280 case ICKind::GlobalLoadIC:
281 case ICKind::GlobalStoreIC: {
282 ASSERT(profileData.IsTaggedArray());
283 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
284 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
285 }
286 default:
287 UNREACHABLE();
288 break;
289 }
290 return ICState::UNINIT;
291 }
292 } // namespace panda::ecmascript
293