• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         ASSERT(profileTypeInfo_->Get(index + 1).IsUndefined());
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             LOG_ECMA(FATAL) << "this branch is unreachable";
221             UNREACHABLE();
222             break;
223     }
224 }
225 
ICStateToString(ProfileTypeAccessor::ICState state)226 std::string ProfileTypeAccessor::ICStateToString(ProfileTypeAccessor::ICState state)
227 {
228     switch (state) {
229         case ICState::UNINIT:
230             return "uninit";
231         case ICState::MONO:
232             return "mono";
233         case ICState::POLY:
234             return "poly";
235         case ICState::MEGA:
236             return "mega";
237         default:
238             LOG_ECMA(FATAL) << "this branch is unreachable";
239             UNREACHABLE();
240             break;
241     }
242 }
243 
GetICState() const244 ProfileTypeAccessor::ICState ProfileTypeAccessor::GetICState() const
245 {
246     auto profileData = profileTypeInfo_->Get(slotId_);
247     if (profileData.IsUndefined()) {
248         return ICState::UNINIT;
249     }
250 
251     if (profileData.IsHole()) {
252         return ICState::MEGA;
253     }
254 
255     switch (kind_) {
256         case ICKind::NamedLoadIC:
257         case ICKind::NamedStoreIC:
258             if (profileData.IsWeak()) {
259                 return ICState::MONO;
260             }
261             ASSERT(profileData.IsTaggedArray());
262             return ICState::POLY;
263         case ICKind::LoadIC:
264         case ICKind::StoreIC: {
265             if (profileData.IsWeak()) {
266                 return ICState::MONO;
267             }
268             if (profileData.IsTaggedArray()) {
269                 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
270                 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
271             }
272             profileData = profileTypeInfo_->Get(slotId_ + 1);
273             TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
274             return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
275         }
276         case ICKind::NamedGlobalLoadIC:
277         case ICKind::NamedGlobalStoreIC:
278         case ICKind::NamedGlobalTryLoadIC:
279         case ICKind::NamedGlobalTryStoreIC:
280             ASSERT(profileData.IsPropertyBox());
281             return ICState::MONO;
282         case ICKind::GlobalLoadIC:
283         case ICKind::GlobalStoreIC: {
284             ASSERT(profileData.IsTaggedArray());
285             TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
286             return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
287         }
288         default:
289             LOG_ECMA(FATAL) << "this branch is unreachable";
290             UNREACHABLE();
291             break;
292     }
293     return ICState::UNINIT;
294 }
295 }  // namespace panda::ecmascript
296