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, ¬HeapObject);
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(¬HeapObject);
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, ¬HeapObject);
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(¬HeapObject);
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