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