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 
20 namespace panda::ecmascript::kungfu {
NamedICAccessor(Variable* cachedHandler, Label *tryICHandler)21 void 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 
ValuedICAccessor(Variable* cachedHandler, Label *tryICHandler, Label* tryElementIC)91 void 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 
LoadICByName( Variable *result, Label *tryFastPath, Label *slowPath, Label *success, ProfileOperation callback)151 void 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 
StoreICByName(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)168 void 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 
LoadICByValue( Variable *result, Label *tryFastPath, Label *slowPath, Label *success, ProfileOperation callback)186 void 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 
StoreICByValue(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)247 void 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 
TryLoadGlobalICByName(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)272 void 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 
TryStoreGlobalICByName(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)293 void 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