• 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/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