• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 #include "ecmascript/compiler/ic_stub_builder.h"
16 
17 #include "ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h"
18 #include "ecmascript/ic/mega_ic_cache.h"
19 
20 namespace panda::ecmascript::kungfu {
21 template<ICStubType type>
NamedICAccessorWithMega(Variable * cachedHandler,Label * tryICHandler)22 void ICStubBuilder::NamedICAccessorWithMega(Variable *cachedHandler, Label *tryICHandler)
23 {
24     auto env = GetEnvironment();
25     Label receiverIsHeapObject(env);
26     BRANCH_LIKELY(TaggedIsHeapObject(receiver_), &receiverIsHeapObject, slowPath_);
27     Bind(&receiverIsHeapObject);
28     {
29         // This function is only invoked by the JIT, so it is assumed that profiletypeinfo must exist and the first slot
30         // must be a hole, thus no checks are performed
31         Label exit(env);
32         Label find(env);
33         GateRef hclass = LoadHClass(receiver_);
34         GateRef hash = HashFromHclassAndStringKey(glue_, hclass, propKey_);
35         GateRef prop = PtrAdd(megaStubCache_,
36                               PtrMul(ZExtInt32ToPtr(hash), IntPtr(MegaICCache::PropertyKey::GetPropertyKeySize())));
37         GateRef propHclass =
38             Load(VariableType::JS_POINTER(), prop, IntPtr(MegaICCache::PropertyKey::GetHclassOffset()));
39         GateRef propKey = Load(VariableType::JS_ANY(), prop, IntPtr(MegaICCache::PropertyKey::GetKeyOffset()));
40         GateRef hclassIsEqual = IntPtrEqual(hclass, propHclass);
41         GateRef keyIsEqual = IntPtrEqual(propKey_, propKey);
42         // profiling code
43         IncMegaProbeCount(glue_);
44         BRANCH_LIKELY(BitAnd(hclassIsEqual, keyIsEqual), &find, slowPath_);
45         Bind(&find);
46         {
47             cachedHandler->WriteVariable(
48                 Load(VariableType::JS_ANY(), prop, IntPtr(MegaICCache::PropertyKey::GetResultsOffset())));
49             // profiling code
50             IncMegaHitCount(glue_);
51             Jump(tryICHandler);
52         }
53     }
54 }
55 
56 template<ICStubType type>
NamedICAccessor(Variable * cachedHandler,Label * tryICHandler)57 void ICStubBuilder::NamedICAccessor(Variable* cachedHandler, Label *tryICHandler)
58 {
59     auto env = GetEnvironment();
60     Label receiverIsHeapObject(env);
61     Label receiverNotHeapObject(env);
62     Label tryIC(env);
63     if constexpr (type == ICStubType::LOAD) {
64         BRANCH_LIKELY(TaggedIsHeapObject(receiver_), &receiverIsHeapObject, &receiverNotHeapObject);
65     } else {
66         BRANCH_LIKELY(TaggedIsHeapObject(receiver_), &receiverIsHeapObject, slowPath_);
67     }
68     Bind(&receiverIsHeapObject);
69     {
70         BRANCH_UNLIKELY(TaggedIsUndefined(profileTypeInfo_), tryFastPath_, &tryIC);
71         Bind(&tryIC);
72         {
73             Label isHeapObject(env);
74             Label notHeapObject(env);
75             GateRef firstValue = GetValueFromTaggedArray(
76                 profileTypeInfo_, slotId_);
77             BRANCH(TaggedIsHeapObject(firstValue), &isHeapObject, &notHeapObject);
78             Bind(&isHeapObject);
79             {
80                 GateRef secondValue = GetValueFromTaggedArray(profileTypeInfo_, Int32Add(slotId_, Int32(1)));
81                 cachedHandler->WriteVariable(secondValue);
82                 Label tryPoly(env);
83                 GateRef hclass = LoadHClass(receiver_);
84                 BRANCH(Equal(LoadObjectFromWeakRef(firstValue), hclass),
85                        tryICHandler,
86                        &tryPoly);
87                 Bind(&tryPoly);
88                 {
89                     cachedHandler->WriteVariable(CheckPolyHClass(firstValue, hclass));
90                     BRANCH(TaggedIsHole(cachedHandler->ReadVariable()), slowPath_, tryICHandler);
91                 }
92             }
93             Bind(&notHeapObject);
94             {
95                 BRANCH(TaggedIsUndefined(firstValue), slowPath_, tryFastPath_);
96             }
97         }
98     }
99     if constexpr (type == ICStubType::STORE) {
100         return;
101     }
102     Bind(&receiverNotHeapObject);
103     {
104         Label tryNumber(env);
105         Label profileNotUndefined(env);
106         BRANCH(TaggedIsNumber(receiver_), &tryNumber, slowPath_);
107         Bind(&tryNumber);
108         {
109             BRANCH(TaggedIsUndefined(profileTypeInfo_), slowPath_, &profileNotUndefined);
110             Bind(&profileNotUndefined);
111             {
112                 GateRef firstValue = GetValueFromTaggedArray(profileTypeInfo_, slotId_);
113                 GateRef secondValue = GetValueFromTaggedArray(profileTypeInfo_, Int32Add(slotId_, Int32(1)));
114                 cachedHandler->WriteVariable(secondValue);
115                 Label isHeapObject(env);
116                 BRANCH(TaggedIsHeapObject(firstValue), &isHeapObject, slowPath_)
117                 Bind(&isHeapObject);
118                 {
119                     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
120                     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue_, glueGlobalEnvOffset);
121                     auto numberFunction = GetGlobalEnvValue(VariableType::JS_ANY(),
122                                                             glueGlobalEnv, GlobalEnv::NUMBER_FUNCTION_INDEX);
123                     GateRef ctorProtoOrHC =
124                             Load(VariableType::JS_POINTER(), numberFunction,
125                                  IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
126                     BRANCH(Equal(LoadObjectFromWeakRef(firstValue), ctorProtoOrHC), tryICHandler, slowPath_);
127                 }
128             }
129         }
130     }
131 }
132 
ValuedICAccessor(Variable * cachedHandler,Label * tryICHandler,Label * tryElementIC)133 void ICStubBuilder::ValuedICAccessor(Variable* cachedHandler, Label *tryICHandler, Label* tryElementIC)
134 {
135     auto env = GetEnvironment();
136     Label receiverIsHeapObject(env);
137 
138     BRANCH(TaggedIsHeapObject(receiver_), &receiverIsHeapObject, slowPath_);
139     Bind(&receiverIsHeapObject);
140     {
141         Label tryIC(env);
142         BRANCH_UNLIKELY(TaggedIsUndefined(profileTypeInfo_), tryFastPath_, &tryIC);
143         Bind(&tryIC);
144         {
145             Label isHeapObject(env);
146             Label notHeapObject(env);
147             GateRef firstValue = GetValueFromTaggedArray(
148                 profileTypeInfo_, slotId_);
149             BRANCH(TaggedIsHeapObject(firstValue), &isHeapObject, &notHeapObject);
150             Bind(&isHeapObject);
151             {
152                 Label tryPoly(env);
153                 Label tryWithElementPoly(env);
154                 GateRef hclass = LoadHClass(receiver_);
155                 BRANCH(Equal(LoadObjectFromWeakRef(firstValue), hclass),
156                        tryElementIC,
157                        &tryPoly);
158                 Bind(&tryPoly);
159                 {
160                     Label firstIsKey(env);
161                     BRANCH(Int64Equal(firstValue, propKey_), &firstIsKey, &tryWithElementPoly);
162                     Bind(&firstIsKey);
163                     {
164                         GateRef handler = CheckPolyHClass(cachedHandler->ReadVariable(), hclass);
165                         cachedHandler->WriteVariable(handler);
166                         BRANCH(TaggedIsHole(cachedHandler->ReadVariable()), slowPath_, tryICHandler);
167                     }
168                     Bind(&tryWithElementPoly);
169                     {
170                         Label checkSecond(env);
171                         Label checkPoly(env);
172                         BRANCH(TaggedIsWeak(firstValue), slowPath_, &checkSecond);
173                         Bind(&checkSecond);
174                         {
175                             BRANCH(TaggedIsHole(cachedHandler->ReadVariable()), &checkPoly, slowPath_);
176                         }
177                         Bind(&checkPoly);
178                         {
179                             cachedHandler->WriteVariable(CheckPolyHClass(firstValue, hclass));
180                             BRANCH(TaggedIsHole(cachedHandler->ReadVariable()), slowPath_, tryElementIC);
181                         }
182                     }
183                 }
184             }
185             Bind(&notHeapObject);
186             {
187                 BRANCH(TaggedIsUndefined(firstValue), slowPath_, tryFastPath_);
188             }
189         }
190     }
191 }
192 
LoadICByName(Variable * result,Label * tryFastPath,Label * slowPath,Label * success,ProfileOperation callback)193 void ICStubBuilder::LoadICByName(
194     Variable *result, Label *tryFastPath, Label *slowPath, Label *success, ProfileOperation callback)
195 {
196     auto env = GetEnvironment();
197     Label loadWithHandler(env);
198 
199     SetLabels(tryFastPath, slowPath, success);
200     DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), Undefined());
201     NamedICAccessor<ICStubType::LOAD>(&cachedHandler, &loadWithHandler);
202     Bind(&loadWithHandler);
203     {
204         GateRef ret = LoadICWithHandler(glue_, receiver_, receiver_, *cachedHandler, callback);
205         result->WriteVariable(ret);
206         BRANCH_UNLIKELY(TaggedIsHole(ret), slowPath_, success_);
207     }
208 }
209 
LoadICByNameWithMega(Variable * result,Label * tryFastPath,Label * slowPath,Label * success,ProfileOperation callback)210 void ICStubBuilder::LoadICByNameWithMega(Variable *result, Label *tryFastPath, Label *slowPath, Label *success,
211                                          ProfileOperation callback)
212 {
213     auto env = GetEnvironment();
214     Label loadWithHandler(env);
215 
216     SetLabels(tryFastPath, slowPath, success);
217     DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), Undefined());
218     NamedICAccessorWithMega<ICStubType::LOAD>(&cachedHandler, &loadWithHandler);
219     Bind(&loadWithHandler);
220     {
221         GateRef ret = LoadICWithHandler(glue_, receiver_, receiver_, *cachedHandler, callback);
222         result->WriteVariable(ret);
223         BRANCH(TaggedIsNotHole(ret), success_, slowPath_);
224     }
225 }
226 
StoreICByName(Variable * result,Label * tryFastPath,Label * slowPath,Label * success)227 void ICStubBuilder::StoreICByName(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)
228 {
229     auto env = GetEnvironment();
230     Label storeWithHandler(env);
231 
232     SetLabels(tryFastPath, slowPath, success);
233     GateRef secondValue = GetValueFromTaggedArray(
234         profileTypeInfo_, Int32Add(slotId_, Int32(1)));
235     DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), secondValue);
236     NamedICAccessor<ICStubType::STORE>(&cachedHandler, &storeWithHandler);
237     Bind(&storeWithHandler);
238     {
239         GateRef ret = StoreICWithHandler(glue_, receiver_, receiver_, value_, *cachedHandler, callback_);
240         result->WriteVariable(ret);
241         BRANCH(TaggedIsHole(ret), slowPath_, success_);
242     }
243 }
244 
StoreICByNameWithMega(Variable * result,Label * tryFastPath,Label * slowPath,Label * success)245 void ICStubBuilder::StoreICByNameWithMega(Variable *result, Label *tryFastPath, Label *slowPath, Label *success)
246 {
247     auto env = GetEnvironment();
248     Label storeWithHandler(env);
249 
250     SetLabels(tryFastPath, slowPath, success);
251     DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), Undefined());
252     NamedICAccessorWithMega<ICStubType::STORE>(&cachedHandler, &storeWithHandler);
253     Bind(&storeWithHandler);
254     {
255         GateRef ret = StoreICWithHandler(glue_, receiver_, receiver_, value_, *cachedHandler, callback_);
256         result->WriteVariable(ret);
257         BRANCH(TaggedIsHole(ret), slowPath_, success_);
258     }
259 }
260 
261 
LoadICByValue(Variable * result,Label * tryFastPath,Label * slowPath,Label * success,ProfileOperation callback)262 void ICStubBuilder::LoadICByValue(
263     Variable *result, Label *tryFastPath, Label *slowPath, Label *success, ProfileOperation callback)
264 {
265     auto env = GetEnvironment();
266     Label loadWithHandler(env);
267     Label loadElement(env);
268     Label handlerInfoIsElement(env);
269     Label handlerInfoNotElement(env);
270     Label handlerInfoIsStringElement(env);
271     Label handlerInfoNotStringElement(env);
272     Label handlerInfoIsTypedArrayElement(env);
273     Label exit(env);
274 
275     SetLabels(tryFastPath, slowPath, success);
276     GateRef secondValue = GetValueFromTaggedArray(
277         profileTypeInfo_, Int32Add(slotId_, Int32(1)));
278     DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), secondValue);
279     DEFVARIABLE(ret, VariableType::JS_ANY(), secondValue);
280 
281     ValuedICAccessor(&cachedHandler, &loadWithHandler, &loadElement);
282     Bind(&loadElement);
283     {
284         GateRef handlerInfo = GetInt64OfTInt(*cachedHandler);
285         BRANCH(IsElement(handlerInfo), &handlerInfoIsElement, &handlerInfoNotElement);
286         Bind(&handlerInfoIsElement);
287         {
288             ret = LoadElement(glue_, receiver_, propKey_);
289             Jump(&exit);
290         }
291         Bind(&handlerInfoNotElement);
292         {
293             BRANCH(IsStringElement(handlerInfo), &handlerInfoIsStringElement, &handlerInfoNotStringElement);
294             Bind(&handlerInfoIsStringElement);
295             {
296                 ret = LoadStringElement(glue_, receiver_, propKey_);
297                 Jump(&exit);
298             }
299             Bind(&handlerInfoNotStringElement);
300             {
301                 BRANCH(IsTypedArrayElement(handlerInfo), &handlerInfoIsTypedArrayElement, &exit);
302                 Bind(&handlerInfoIsTypedArrayElement);
303                 {
304                     GateRef hclass = LoadHClass(receiver_);
305                     GateRef jsType = GetObjectType(hclass);
306                     BuiltinsTypedArrayStubBuilder typedArrayBuilder(reinterpret_cast<StubBuilder*>(this));
307                     ret = typedArrayBuilder.LoadTypedArrayElement(glue_, receiver_, propKey_, jsType);
308                     Jump(&exit);
309                 }
310             }
311         }
312     }
313     Bind(&loadWithHandler);
314     {
315         ret = LoadICWithHandler(glue_, receiver_, receiver_, *cachedHandler, callback);
316         Jump(&exit);
317     }
318     Bind(&exit);
319     result->WriteVariable(*ret);
320     BRANCH(TaggedIsHole(*ret), slowPath_, success_);
321 }
322 
StoreICByValue(Variable * result,Label * tryFastPath,Label * slowPath,Label * success)323 void ICStubBuilder::StoreICByValue(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)
324 {
325     auto env = GetEnvironment();
326     Label storeWithHandler(env);
327     Label storeElement(env);
328     SetLabels(tryFastPath, slowPath, success);
329     GateRef secondValue = GetValueFromTaggedArray(
330         profileTypeInfo_, Int32Add(slotId_, Int32(1)));
331     DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), secondValue);
332     ValuedICAccessor(&cachedHandler, &storeWithHandler, &storeElement);
333     Bind(&storeElement);
334     {
335         GateRef ret = ICStoreElement(glue_, receiver_, propKey_, value_, *cachedHandler,
336                                      true, profileTypeInfo_, Int32Add(slotId_, Int32(1)));
337         result->WriteVariable(ret);
338         BRANCH(TaggedIsHole(ret), slowPath_, success_);
339     }
340     Bind(&storeWithHandler);
341     {
342         GateRef ret = StoreICWithHandler(glue_, receiver_, receiver_, value_, *cachedHandler, callback_);
343         result->WriteVariable(ret);
344         BRANCH(TaggedIsHole(ret), slowPath_, success_);
345     }
346 }
347 
TryLoadGlobalICByName(Variable * result,Label * tryFastPath,Label * slowPath,Label * success)348 void ICStubBuilder::TryLoadGlobalICByName(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)
349 {
350     auto env = GetEnvironment();
351     Label tryIC(env);
352 
353     SetLabels(tryFastPath, slowPath, success);
354     BRANCH(TaggedIsUndefined(profileTypeInfo_), tryFastPath_, &tryIC);
355     Bind(&tryIC);
356     {
357         GateRef handler = GetValueFromTaggedArray(profileTypeInfo_, slotId_);
358         Label isHeapObject(env);
359         BRANCH(TaggedIsHeapObject(handler), &isHeapObject, slowPath_);
360         Bind(&isHeapObject);
361         {
362             GateRef ret = LoadGlobal(handler);
363             result->WriteVariable(ret);
364             BRANCH(TaggedIsHole(ret), slowPath_, success_);
365         }
366     }
367 }
368 
TryStoreGlobalICByName(Variable * result,Label * tryFastPath,Label * slowPath,Label * success)369 void ICStubBuilder::TryStoreGlobalICByName(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)
370 {
371     auto env = GetEnvironment();
372     Label tryIC(env);
373 
374     SetLabels(tryFastPath, slowPath, success);
375     BRANCH(TaggedIsUndefined(profileTypeInfo_), tryFastPath_, &tryIC);
376     Bind(&tryIC);
377     {
378         GateRef handler = GetValueFromTaggedArray(profileTypeInfo_, slotId_);
379         Label isHeapObject(env);
380         BRANCH(TaggedIsHeapObject(handler), &isHeapObject, slowPath_);
381         Bind(&isHeapObject);
382         {
383             GateRef ret = StoreGlobal(glue_, value_, handler);
384             result->WriteVariable(ret);
385             BRANCH(TaggedIsHole(ret), slowPath_, success_);
386         }
387     }
388 }
389 }  // namespace panda::ecmascript::kungfu
390