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).IsHole());
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 profileTypeInfo_->Set(thread_, index, key.GetTaggedValue());
104 const int arrayLength = 2;
105 JSHandle<TaggedArray> newArr = thread_->GetEcmaVM()->GetFactory()->NewTaggedArray(arrayLength);
106 newArr->Set(thread_, 0, GetWeakRef(hclass.GetTaggedValue()));
107 newArr->Set(thread_, 1, handler.GetTaggedValue());
108 profileTypeInfo_->Set(thread_, index + 1, newArr.GetTaggedValue());
109 return;
110 }
111 // for element ic, profileData may hclass or taggedarray
112 if (key.GetTaggedValue() != profileData) {
113 profileTypeInfo_->Set(thread_, index, JSTaggedValue::Hole());
114 profileTypeInfo_->Set(thread_, index + 1, JSTaggedValue::Hole());
115 return;
116 }
117 JSTaggedValue patchValue = profileTypeInfo_->Get(index + 1);
118 ASSERT(patchValue.IsTaggedArray());
119 JSHandle<TaggedArray> arr(thread_, patchValue);
120 const uint32_t step = 2;
121 if (arr->GetLength() > step) { // POLY
122 uint32_t newLen = arr->GetLength() + step;
123 if (newLen > CACHE_MAX_LEN) {
124 profileTypeInfo_->Set(thread_, index, JSTaggedValue::Hole());
125 profileTypeInfo_->Set(thread_, index + 1, JSTaggedValue::Hole());
126 return;
127 }
128 auto factory = thread_->GetEcmaVM()->GetFactory();
129 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(newLen);
130 newArr->Set(thread_, 0, GetWeakRef(hclass.GetTaggedValue()));
131 newArr->Set(thread_, 1, handler.GetTaggedValue());
132 for (uint32_t i = 0; i < arr->GetLength(); i += step) {
133 newArr->Set(thread_, i + step, arr->Get(i));
134 newArr->Set(thread_, i + step + 1, arr->Get(i + 1));
135 }
136 profileTypeInfo_->Set(thread_, index + 1, newArr.GetTaggedValue());
137 return;
138 }
139 // MONO
140 auto factory = thread_->GetEcmaVM()->GetFactory();
141 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(POLY_CASE_NUM);
142 uint32_t arrIndex = 0;
143 newArr->Set(thread_, arrIndex++, arr->Get(0));
144 newArr->Set(thread_, arrIndex++, arr->Get(1));
145 newArr->Set(thread_, arrIndex++, GetWeakRef(hclass.GetTaggedValue()));
146 newArr->Set(thread_, arrIndex++, handler.GetTaggedValue());
147
148 profileTypeInfo_->Set(thread_, index + 1, newArr.GetTaggedValue());
149 }
150
AddGlobalHandlerKey(JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> handler) const151 void ProfileTypeAccessor::AddGlobalHandlerKey(JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> handler) const
152 {
153 auto index = slotId_;
154 const uint8_t step = 2; // key and value pair
155 JSTaggedValue indexVal = profileTypeInfo_->Get(index);
156 if (indexVal.IsUndefined()) {
157 auto factory = thread_->GetEcmaVM()->GetFactory();
158 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(step);
159 newArr->Set(thread_, 0, GetWeakRef(key.GetTaggedValue()));
160 newArr->Set(thread_, 1, handler.GetTaggedValue());
161 profileTypeInfo_->Set(thread_, index, newArr.GetTaggedValue());
162 return;
163 }
164 ASSERT(indexVal.IsTaggedArray());
165 JSHandle<TaggedArray> arr(thread_, indexVal);
166 uint32_t newLen = arr->GetLength() + step;
167 if (newLen > CACHE_MAX_LEN) {
168 profileTypeInfo_->Set(thread_, index, JSTaggedValue::Hole());
169 return;
170 }
171 auto factory = thread_->GetEcmaVM()->GetFactory();
172 JSHandle<TaggedArray> newArr = factory->NewTaggedArray(newLen);
173 newArr->Set(thread_, 0, GetWeakRef(key.GetTaggedValue()));
174 newArr->Set(thread_, 1, handler.GetTaggedValue());
175
176 for (uint32_t i = 0; i < arr->GetLength(); i += step) {
177 newArr->Set(thread_, i + step, arr->Get(i));
178 newArr->Set(thread_, i + step + 1, arr->Get(i + 1));
179 }
180 profileTypeInfo_->Set(thread_, index, newArr.GetTaggedValue());
181 }
182
AddGlobalRecordHandler(JSHandle<JSTaggedValue> handler) const183 void ProfileTypeAccessor::AddGlobalRecordHandler(JSHandle<JSTaggedValue> handler) const
184 {
185 uint32_t index = slotId_;
186 profileTypeInfo_->Set(thread_, index, handler.GetTaggedValue());
187 }
188
SetAsMega() const189 void ProfileTypeAccessor::SetAsMega() const
190 {
191 profileTypeInfo_->Set(thread_, slotId_, JSTaggedValue::Hole());
192 profileTypeInfo_->Set(thread_, slotId_ + 1, JSTaggedValue::Hole());
193 }
194
ICKindToString(ICKind kind)195 std::string ICKindToString(ICKind kind)
196 {
197 switch (kind) {
198 case ICKind::NamedLoadIC:
199 return "NamedLoadIC";
200 case ICKind::NamedStoreIC:
201 return "NamedStoreIC";
202 case ICKind::LoadIC:
203 return "LoadIC";
204 case ICKind::StoreIC:
205 return "StoreIC";
206 case ICKind::NamedGlobalLoadIC:
207 return "NamedGlobalLoadIC";
208 case ICKind::NamedGlobalStoreIC:
209 return "NamedGlobalStoreIC";
210 case ICKind::NamedGlobalTryLoadIC:
211 return "NamedGlobalTryLoadIC";
212 case ICKind::NamedGlobalTryStoreIC:
213 return "NamedGlobalTryStoreIC";
214 case ICKind::GlobalLoadIC:
215 return "GlobalLoadIC";
216 case ICKind::GlobalStoreIC:
217 return "GlobalStoreIC";
218 default:
219 LOG_ECMA(FATAL) << "this branch is unreachable";
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 LOG_ECMA(FATAL) << "this branch is unreachable";
238 UNREACHABLE();
239 break;
240 }
241 }
242
GetICState() const243 ProfileTypeAccessor::ICState ProfileTypeAccessor::GetICState() const
244 {
245 auto profileData = profileTypeInfo_->Get(slotId_);
246 if (profileData.IsUndefined()) {
247 return ICState::UNINIT;
248 }
249
250 if (profileData.IsHole()) {
251 return ICState::MEGA;
252 }
253
254 switch (kind_) {
255 case ICKind::NamedLoadIC:
256 case ICKind::NamedStoreIC:
257 if (profileData.IsWeak()) {
258 return ICState::MONO;
259 }
260 ASSERT(profileData.IsTaggedArray());
261 return ICState::POLY;
262 case ICKind::LoadIC:
263 case ICKind::StoreIC: {
264 if (profileData.IsWeak()) {
265 return ICState::MONO;
266 }
267 if (profileData.IsTaggedArray()) {
268 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
269 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
270 }
271 profileData = profileTypeInfo_->Get(slotId_ + 1);
272 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
273 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
274 }
275 case ICKind::NamedGlobalLoadIC:
276 case ICKind::NamedGlobalStoreIC:
277 case ICKind::NamedGlobalTryLoadIC:
278 case ICKind::NamedGlobalTryStoreIC:
279 ASSERT(profileData.IsPropertyBox());
280 return ICState::MONO;
281 case ICKind::GlobalLoadIC:
282 case ICKind::GlobalStoreIC: {
283 ASSERT(profileData.IsTaggedArray());
284 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
285 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
286 }
287 default:
288 LOG_ECMA(FATAL) << "this branch is unreachable";
289 UNREACHABLE();
290 break;
291 }
292 return ICState::UNINIT;
293 }
294 } // namespace panda::ecmascript
295