• 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 "libpandabase/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(thread_, 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(thread_, 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(thread_, i) == JSTaggedValue::Undefined()) {
73                 continue;
74             }
75             cache->Set(JSHClass::Cast(arr->Get(thread_, i).GetWeakReferentUnChecked()), keyForMegaIC.GetTaggedValue(),
76                        arr->Get(thread_, 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(thread_, i));
88         newArr->Set(thread_, i + 1, arr->Get(thread_, 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(thread_, 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(thread_, index));
121     newArr->Set(thread_, arrIndex++, profileTypeInfo_->GetIcSlot(thread_, 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(thread_, 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(thread_, 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(thread_, i));
170             newArr->Set(thread_, i + step + 1, arr->Get(thread_, 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(thread_, 0));
180     newArr->Set(thread_, arrIndex++, arr->Get(thread_, 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(thread_, 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(thread_, i));
215         newArr->Set(thread_, i + step + 1, arr->Get(thread_, 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 
SetAsMegaIfUndefined() const249 void ProfileTypeAccessor::SetAsMegaIfUndefined() const
250 {
251     if (profileTypeInfo_->GetIcSlot(thread_, slotId_).IsUndefined()) {
252         SetAsMega();
253     }
254 }
255 
SetAsMegaForTrace(JSTaggedValue value) const256 void ProfileTypeAccessor::SetAsMegaForTrace(JSTaggedValue value) const
257 {
258     if (IsGlobalIC(kind_)) {
259         profileTypeInfo_->SetIcSlot(thread_, slotId_, JSTaggedValue::Hole());
260     } else {
261         profileTypeInfo_->SetMultiIcSlotLocked(thread_, slotId_,
262             JSTaggedValue::Hole(), slotId_ + 1, value);
263     }
264 }
265 
ICKindToString(ICKind kind)266 std::string ICKindToString(ICKind kind)
267 {
268     switch (kind) {
269         case ICKind::NamedLoadIC:
270             return "NamedLoadIC";
271         case ICKind::NamedStoreIC:
272             return "NamedStoreIC";
273         case ICKind::LoadIC:
274             return "LoadIC";
275         case ICKind::StoreIC:
276             return "StoreIC";
277         case ICKind::NamedGlobalLoadIC:
278             return "NamedGlobalLoadIC";
279         case ICKind::NamedGlobalStoreIC:
280             return "NamedGlobalStoreIC";
281         case ICKind::NamedGlobalTryLoadIC:
282             return "NamedGlobalTryLoadIC";
283         case ICKind::NamedGlobalTryStoreIC:
284             return "NamedGlobalTryStoreIC";
285         case ICKind::GlobalLoadIC:
286             return "GlobalLoadIC";
287         case ICKind::GlobalStoreIC:
288             return "GlobalStoreIC";
289         default:
290             LOG_ECMA(FATAL) << "this branch is unreachable";
291             UNREACHABLE();
292             break;
293     }
294 }
295 
ICStateToString(ProfileTypeAccessor::ICState state)296 std::string ProfileTypeAccessor::ICStateToString(ProfileTypeAccessor::ICState state)
297 {
298     switch (state) {
299         case ICState::UNINIT:
300             return "uninit";
301         case ICState::MONO:
302             return "mono";
303         case ICState::POLY:
304             return "poly";
305         case ICState::MEGA:
306             return "mega";
307         case ICState::IC_MEGA:
308             return "ic_mega";
309         default:
310             LOG_ECMA(FATAL) << "this branch is unreachable";
311             UNREACHABLE();
312             break;
313     }
314 }
GetMegaState() const315 ProfileTypeAccessor::ICState ProfileTypeAccessor::GetMegaState() const
316 {
317     if (IsGlobalIC(kind_)) {
318         return ICState::MEGA;
319     }
320     auto profileDataSecond = profileTypeInfo_->Get(thread_, slotId_ + 1);
321     if (profileDataSecond.IsString()) {
322         return ICState::IC_MEGA;
323     } else {
324         return ICState::MEGA;
325     }
326 }
327 
GetICState() const328 ProfileTypeAccessor::ICState ProfileTypeAccessor::GetICState() const
329 {
330     auto profileData = profileTypeInfo_->GetIcSlot(thread_, slotId_);
331     if (profileData.IsUndefined()) {
332         return ICState::UNINIT;
333     }
334 
335     if (profileData.IsHole()) {
336         return GetMegaState();
337     }
338 
339     switch (kind_) {
340         case ICKind::NamedLoadIC:
341         case ICKind::NamedStoreIC:
342             if (profileData.IsWeak()) {
343                 return ICState::MONO;
344             }
345             ASSERT(profileData.IsTaggedArray());
346             return ICState::POLY;
347         case ICKind::LoadIC:
348         case ICKind::StoreIC: {
349             if (profileData.IsWeak()) {
350                 return ICState::MONO;
351             }
352             if (profileData.IsTaggedArray()) {
353                 TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
354                 return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
355             }
356             profileData = profileTypeInfo_->GetIcSlot(thread_, slotId_ + 1);
357             TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
358             return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
359         }
360         case ICKind::NamedGlobalLoadIC:
361         case ICKind::NamedGlobalStoreIC:
362         case ICKind::NamedGlobalTryLoadIC:
363         case ICKind::NamedGlobalTryStoreIC:
364             ASSERT(profileData.IsPropertyBox());
365             return ICState::MONO;
366         case ICKind::GlobalLoadIC:
367         case ICKind::GlobalStoreIC: {
368             ASSERT(profileData.IsTaggedArray());
369             TaggedArray *array = TaggedArray::Cast(profileData.GetTaggedObject());
370             return array->GetLength() == MONO_CASE_NUM ? ICState::MONO : ICState::POLY; // 2 : test case
371         }
372         default:
373             LOG_ECMA(FATAL) << "this branch is unreachable";
374             UNREACHABLE();
375             break;
376     }
377     return ICState::UNINIT;
378 }
379 }  // namespace panda::ecmascript
380