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 ¬DesignatePrimitive,
94 PrimitiveType primitiveType, PrimitiveLoadICInfo info)
95 {
96 size_t globalEnvIndex = 0;
97 switch (primitiveType) {
98 case PrimitiveType::PRIMITIVE_BOOLEAN:
99 BRANCH(TaggedIsBoolean(receiver_), &tryDesignatePrimitive, ¬DesignatePrimitive);
100 globalEnvIndex = GlobalEnv::BOOLEAN_FUNCTION_INDEX;
101 break;
102 case PrimitiveType::PRIMITIVE_NUMBER:
103 BRANCH(TaggedIsNumber(receiver_), &tryDesignatePrimitive, ¬DesignatePrimitive);
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(¬Number);
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, ¬HeapObject);
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(¬HeapObject);
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, ¬HeapObject);
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(¬HeapObject);
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