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/stub_builder-inl.h"
19
20namespace panda::ecmascript::kungfu {
21void ICStubBuilder::NamedICAccessor(Variable* cachedHandler, Label *tryICHandler)
22{
23    auto env = GetEnvironment();
24    Label receiverIsHeapObject(env);
25    Label receiverNotHeapObject(env);
26    Label tryIC(env);
27
28    BRANCH(TaggedIsHeapObject(receiver_), &receiverIsHeapObject, &receiverNotHeapObject);
29    Bind(&receiverIsHeapObject);
30    {
31        BRANCH(TaggedIsUndefined(profileTypeInfo_), tryFastPath_, &tryIC);
32        Bind(&tryIC);
33        {
34            Label isHeapObject(env);
35            Label notHeapObject(env);
36            GateRef firstValue = GetValueFromTaggedArray(
37                profileTypeInfo_, slotId_);
38            BRANCH(TaggedIsHeapObject(firstValue), &isHeapObject, &notHeapObject);
39            Bind(&isHeapObject);
40            {
41                GateRef secondValue = GetValueFromTaggedArray(profileTypeInfo_, Int32Add(slotId_, Int32(1)));
42                cachedHandler->WriteVariable(secondValue);
43                Label tryPoly(env);
44                GateRef hclass = LoadHClass(receiver_);
45                BRANCH(Equal(LoadObjectFromWeakRef(firstValue), hclass),
46                       tryICHandler,
47                       &tryPoly);
48                Bind(&tryPoly);
49                {
50                    cachedHandler->WriteVariable(CheckPolyHClass(firstValue, hclass));
51                    BRANCH(TaggedIsHole(cachedHandler->ReadVariable()), slowPath_, tryICHandler);
52                }
53            }
54            Bind(&notHeapObject);
55            {
56                BRANCH(TaggedIsUndefined(firstValue), slowPath_, tryFastPath_);
57            }
58        }
59    }
60    Bind(&receiverNotHeapObject);
61    {
62        Label tryNumber(env);
63        Label profileNotUndefined(env);
64        BRANCH(TaggedIsNumber(receiver_), &tryNumber, slowPath_);
65        Bind(&tryNumber);
66        {
67            BRANCH(TaggedIsUndefined(profileTypeInfo_), slowPath_, &profileNotUndefined);
68            Bind(&profileNotUndefined);
69            {
70                GateRef firstValue = GetValueFromTaggedArray(profileTypeInfo_, slotId_);
71                GateRef secondValue = GetValueFromTaggedArray(profileTypeInfo_, Int32Add(slotId_, Int32(1)));
72                cachedHandler->WriteVariable(secondValue);
73                Label isHeapObject(env);
74                BRANCH(TaggedIsHeapObject(firstValue), &isHeapObject, slowPath_)
75                Bind(&isHeapObject);
76                {
77                    GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
78                    GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue_, glueGlobalEnvOffset);
79                    auto numberFunction = GetGlobalEnvValue(VariableType::JS_ANY(),
80                                                            glueGlobalEnv, GlobalEnv::NUMBER_FUNCTION_INDEX);
81                    GateRef ctorProtoOrHC =
82                            Load(VariableType::JS_POINTER(), numberFunction,
83                                 IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
84                    BRANCH(Equal(LoadObjectFromWeakRef(firstValue), ctorProtoOrHC), tryICHandler, slowPath_);
85                }
86            }
87        }
88    }
89}
90
91void ICStubBuilder::ValuedICAccessor(Variable* cachedHandler, Label *tryICHandler, Label* tryElementIC)
92{
93    auto env = GetEnvironment();
94    Label receiverIsHeapObject(env);
95
96    BRANCH(TaggedIsHeapObject(receiver_), &receiverIsHeapObject, slowPath_);
97    Bind(&receiverIsHeapObject);
98    {
99        Label tryIC(env);
100        BRANCH(TaggedIsUndefined(profileTypeInfo_), tryFastPath_, &tryIC);
101        Bind(&tryIC);
102        {
103            Label isHeapObject(env);
104            Label notHeapObject(env);
105            GateRef firstValue = GetValueFromTaggedArray(
106                profileTypeInfo_, slotId_);
107            BRANCH(TaggedIsHeapObject(firstValue), &isHeapObject, &notHeapObject);
108            Bind(&isHeapObject);
109            {
110                Label tryPoly(env);
111                Label tryWithElementPoly(env);
112                GateRef hclass = LoadHClass(receiver_);
113                BRANCH(Equal(LoadObjectFromWeakRef(firstValue), hclass),
114                       tryElementIC,
115                       &tryPoly);
116                Bind(&tryPoly);
117                {
118                    Label firstIsKey(env);
119                    BRANCH(Int64Equal(firstValue, propKey_), &firstIsKey, &tryWithElementPoly);
120                    Bind(&firstIsKey);
121                    {
122                        GateRef handler = CheckPolyHClass(cachedHandler->ReadVariable(), hclass);
123                        cachedHandler->WriteVariable(handler);
124                        BRANCH(TaggedIsHole(cachedHandler->ReadVariable()), slowPath_, tryICHandler);
125                    }
126                    Bind(&tryWithElementPoly);
127                    {
128                        Label checkSecond(env);
129                        Label checkPoly(env);
130                        BRANCH(TaggedIsWeak(firstValue), slowPath_, &checkSecond);
131                        Bind(&checkSecond);
132                        {
133                            BRANCH(TaggedIsHole(cachedHandler->ReadVariable()), &checkPoly, slowPath_);
134                        }
135                        Bind(&checkPoly);
136                        {
137                            cachedHandler->WriteVariable(CheckPolyHClass(firstValue, hclass));
138                            BRANCH(TaggedIsHole(cachedHandler->ReadVariable()), slowPath_, tryElementIC);
139                        }
140                    }
141                }
142            }
143            Bind(&notHeapObject);
144            {
145                BRANCH(TaggedIsUndefined(firstValue), slowPath_, tryFastPath_);
146            }
147        }
148    }
149}
150
151void ICStubBuilder::LoadICByName(
152    Variable *result, Label *tryFastPath, Label *slowPath, Label *success, ProfileOperation callback)
153{
154    auto env = GetEnvironment();
155    Label loadWithHandler(env);
156
157    SetLabels(tryFastPath, slowPath, success);
158    DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), Undefined());
159    NamedICAccessor(&cachedHandler, &loadWithHandler);
160    Bind(&loadWithHandler);
161    {
162        GateRef ret = LoadICWithHandler(glue_, receiver_, receiver_, *cachedHandler, callback);
163        result->WriteVariable(ret);
164        BRANCH(TaggedIsHole(ret), slowPath_, success_);
165    }
166}
167
168void ICStubBuilder::StoreICByName(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)
169{
170    auto env = GetEnvironment();
171    Label storeWithHandler(env);
172
173    SetLabels(tryFastPath, slowPath, success);
174    GateRef secondValue = GetValueFromTaggedArray(
175        profileTypeInfo_, Int32Add(slotId_, Int32(1)));
176    DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), secondValue);
177    NamedICAccessor(&cachedHandler, &storeWithHandler);
178    Bind(&storeWithHandler);
179    {
180        GateRef ret = StoreICWithHandler(glue_, receiver_, receiver_, value_, *cachedHandler, callback_);
181        result->WriteVariable(ret);
182        BRANCH(TaggedIsHole(ret), slowPath_, success_);
183    }
184}
185
186void ICStubBuilder::LoadICByValue(
187    Variable *result, Label *tryFastPath, Label *slowPath, Label *success, ProfileOperation callback)
188{
189    auto env = GetEnvironment();
190    Label loadWithHandler(env);
191    Label loadElement(env);
192    Label handlerInfoIsElement(env);
193    Label handlerInfoNotElement(env);
194    Label handlerInfoIsStringElement(env);
195    Label handlerInfoNotStringElement(env);
196    Label handlerInfoIsTypedArrayElement(env);
197    Label exit(env);
198
199    SetLabels(tryFastPath, slowPath, success);
200    GateRef secondValue = GetValueFromTaggedArray(
201        profileTypeInfo_, Int32Add(slotId_, Int32(1)));
202    DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), secondValue);
203    DEFVARIABLE(ret, VariableType::JS_ANY(), secondValue);
204
205    ValuedICAccessor(&cachedHandler, &loadWithHandler, &loadElement);
206    Bind(&loadElement);
207    {
208        GateRef handlerInfo = GetInt64OfTInt(*cachedHandler);
209        BRANCH(IsElement(handlerInfo), &handlerInfoIsElement, &handlerInfoNotElement);
210        Bind(&handlerInfoIsElement);
211        {
212            ret = LoadElement(glue_, receiver_, propKey_);
213            Jump(&exit);
214        }
215        Bind(&handlerInfoNotElement);
216        {
217            BRANCH(IsStringElement(handlerInfo), &handlerInfoIsStringElement, &handlerInfoNotStringElement);
218            Bind(&handlerInfoIsStringElement);
219            {
220                ret = LoadStringElement(glue_, receiver_, propKey_);
221                Jump(&exit);
222            }
223            Bind(&handlerInfoNotStringElement);
224            {
225                BRANCH(IsTypedArrayElement(handlerInfo), &handlerInfoIsTypedArrayElement, &exit);
226                Bind(&handlerInfoIsTypedArrayElement);
227                {
228                    GateRef hclass = LoadHClass(receiver_);
229                    GateRef jsType = GetObjectType(hclass);
230                    BuiltinsTypedArrayStubBuilder typedArrayBuilder(reinterpret_cast<StubBuilder*>(this));
231                    ret = typedArrayBuilder.LoadTypedArrayElement(glue_, receiver_, propKey_, jsType);
232                    Jump(&exit);
233                }
234            }
235        }
236    }
237    Bind(&loadWithHandler);
238    {
239        ret = LoadICWithHandler(glue_, receiver_, receiver_, *cachedHandler, callback);
240        Jump(&exit);
241    }
242    Bind(&exit);
243    result->WriteVariable(*ret);
244    BRANCH(TaggedIsHole(*ret), slowPath_, success_);
245}
246
247void ICStubBuilder::StoreICByValue(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)
248{
249    auto env = GetEnvironment();
250    Label storeWithHandler(env);
251    Label storeElement(env);
252    SetLabels(tryFastPath, slowPath, success);
253    GateRef secondValue = GetValueFromTaggedArray(
254        profileTypeInfo_, Int32Add(slotId_, Int32(1)));
255    DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), secondValue);
256    ValuedICAccessor(&cachedHandler, &storeWithHandler, &storeElement);
257    Bind(&storeElement);
258    {
259        GateRef ret = ICStoreElement(glue_, receiver_, propKey_, value_, *cachedHandler,
260                                     true, profileTypeInfo_, Int32Add(slotId_, Int32(1)));
261        result->WriteVariable(ret);
262        BRANCH(TaggedIsHole(ret), slowPath_, success_);
263    }
264    Bind(&storeWithHandler);
265    {
266        GateRef ret = StoreICWithHandler(glue_, receiver_, receiver_, value_, *cachedHandler, callback_);
267        result->WriteVariable(ret);
268        BRANCH(TaggedIsHole(ret), slowPath_, success_);
269    }
270}
271
272void ICStubBuilder::TryLoadGlobalICByName(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)
273{
274    auto env = GetEnvironment();
275    Label tryIC(env);
276
277    SetLabels(tryFastPath, slowPath, success);
278    BRANCH(TaggedIsUndefined(profileTypeInfo_), tryFastPath_, &tryIC);
279    Bind(&tryIC);
280    {
281        GateRef handler = GetValueFromTaggedArray(profileTypeInfo_, slotId_);
282        Label isHeapObject(env);
283        BRANCH(TaggedIsHeapObject(handler), &isHeapObject, slowPath_);
284        Bind(&isHeapObject);
285        {
286            GateRef ret = LoadGlobal(handler);
287            result->WriteVariable(ret);
288            BRANCH(TaggedIsHole(ret), slowPath_, success_);
289        }
290    }
291}
292
293void ICStubBuilder::TryStoreGlobalICByName(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)
294{
295    auto env = GetEnvironment();
296    Label tryIC(env);
297
298    SetLabels(tryFastPath, slowPath, success);
299    BRANCH(TaggedIsUndefined(profileTypeInfo_), tryFastPath_, &tryIC);
300    Bind(&tryIC);
301    {
302        GateRef handler = GetValueFromTaggedArray(profileTypeInfo_, slotId_);
303        Label isHeapObject(env);
304        BRANCH(TaggedIsHeapObject(handler), &isHeapObject, slowPath_);
305        Bind(&isHeapObject);
306        {
307            GateRef ret = StoreGlobal(glue_, value_, handler);
308            result->WriteVariable(ret);
309            BRANCH(TaggedIsHole(ret), slowPath_, success_);
310        }
311    }
312}
313}  // namespace panda::ecmascript::kungfu
314