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/access_object_stub_builder.h"
16#include "ecmascript/compiler/ic_stub_builder.h"
17#include "ecmascript/compiler/interpreter_stub-inl.h"
18#include "ecmascript/compiler/profiler_stub_builder.h"
19#include "ecmascript/compiler/rt_call_signature.h"
20#include "ecmascript/compiler/stub_builder-inl.h"
21#include "ecmascript/ic/profile_type_info.h"
22
23namespace panda::ecmascript::kungfu {
24GateRef AccessObjectStubBuilder::LoadObjByName(GateRef glue, GateRef receiver, GateRef prop, const StringIdInfo &info,
25                                               GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
26{
27    auto env = GetEnvironment();
28    Label entry(env);
29    env->SubCfgEntry(&entry);
30    Label exit(env);
31    Label tryFastPath(env);
32    Label slowPath(env);
33    Label tryPreDump(env);
34
35    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
36    GateRef value = 0;
37    ICStubBuilder builder(this);
38    builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
39    builder.LoadICByName(&result, &tryFastPath, &tryPreDump, &exit, callback);
40    Bind(&tryFastPath);
41    {
42        GateRef propKey = ResolvePropKey(glue, prop, info);
43        result = GetPropertyByName(glue, receiver, propKey, callback, True());
44        BRANCH(TaggedIsHole(*result), &slowPath, &exit);
45    }
46    Bind(&tryPreDump);
47    {
48        callback.TryPreDump();
49        Jump(&slowPath);
50    }
51    Bind(&slowPath);
52    {
53        GateRef propKey = ResolvePropKey(glue, prop, info);
54        result =
55            CallRuntime(glue, RTSTUB_ID(LoadICByName), {profileTypeInfo, receiver, propKey, IntToTaggedInt(slotId)});
56        Jump(&exit);
57    }
58    Bind(&exit);
59    auto ret = *result;
60    env->SubCfgExit();
61    return ret;
62}
63
64GateRef AccessObjectStubBuilder::LoadPrivatePropertyByName(
65    GateRef glue, GateRef receiver, GateRef key, GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
66{
67    auto env = GetEnvironment();
68    Label entry(env);
69    env->SubCfgEntry(&entry);
70    Label exit(env);
71    Label tryFastPath(env);
72    Label slowPath(env);
73    Label tryPreDump(env);
74
75    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
76    GateRef value = 0;
77    ICStubBuilder builder(this);
78    builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
79    builder.LoadICByName(&result, &tryFastPath, &tryPreDump, &exit, callback);
80    Bind(&tryFastPath);
81    {
82        result = GetPropertyByName(glue, receiver, key, callback, True());
83        BRANCH(TaggedIsHole(*result), &slowPath, &exit);
84    }
85    Bind(&tryPreDump);
86    {
87        callback.TryPreDump();
88        Jump(&slowPath);
89    }
90    Bind(&slowPath);
91    {
92        result = CallRuntime(glue, RTSTUB_ID(LoadICByName), {profileTypeInfo, receiver, key, IntToTaggedInt(slotId)});
93        Jump(&exit);
94    }
95    Bind(&exit);
96    auto ret = *result;
97    env->SubCfgExit();
98    return ret;
99}
100
101// Used for deprecated bytecodes which will not support ic
102GateRef AccessObjectStubBuilder::DeprecatedLoadObjByName(GateRef glue, GateRef receiver, GateRef propKey)
103{
104    auto env = GetEnvironment();
105    Label entry(env);
106    env->SubCfgEntry(&entry);
107    Label exit(env);
108    Label fastPath(env);
109    Label slowPath(env);
110
111    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
112    BRANCH(TaggedIsHeapObject(receiver), &fastPath, &slowPath);
113    Bind(&fastPath);
114    {
115        result = GetPropertyByName(glue, receiver, propKey, ProfileOperation(), True());
116        BRANCH(TaggedIsHole(*result), &slowPath, &exit);
117    }
118    Bind(&slowPath);
119    {
120        result = CallRuntime(glue, RTSTUB_ID(LoadICByName),
121            { Undefined(), receiver, propKey, IntToTaggedInt(Int32(0xFF)) });  // 0xFF: invalid slot id
122        Jump(&exit);
123    }
124    Bind(&exit);
125    auto ret = *result;
126    env->SubCfgExit();
127    return ret;
128}
129
130GateRef AccessObjectStubBuilder::StoreObjByName(GateRef glue, GateRef receiver, GateRef prop, const StringIdInfo &info,
131                                                GateRef value, GateRef profileTypeInfo, GateRef slotId,
132                                                ProfileOperation callback)
133{
134    auto env = GetEnvironment();
135    Label entry(env);
136    env->SubCfgEntry(&entry);
137    Label exit(env);
138    Label tryFastPath(env);
139    Label slowPath(env);
140    Label tryPreDump(env);
141
142    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
143    ICStubBuilder builder(this);
144    builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, callback);
145    builder.StoreICByName(&result, &tryFastPath, &tryPreDump, &exit);
146    Bind(&tryFastPath);
147    {
148        GateRef propKey = ResolvePropKey(glue, prop, info);
149        result = SetPropertyByName(glue, receiver, propKey, value, false, True(), callback);
150        BRANCH(TaggedIsHole(*result), &slowPath, &exit);
151    }
152    Bind(&tryPreDump);
153    {
154        callback.TryPreDump();
155        Jump(&slowPath);
156    }
157    Bind(&slowPath);
158    {
159        GateRef propKey = ResolvePropKey(glue, prop, info);
160        result = CallRuntime(
161            glue, RTSTUB_ID(StoreICByName), {profileTypeInfo, receiver, propKey, value, IntToTaggedInt(slotId)});
162        Jump(&exit);
163    }
164
165    Bind(&exit);
166    auto ret = *result;
167    env->SubCfgExit();
168    return ret;
169}
170
171GateRef AccessObjectStubBuilder::StorePrivatePropertyByName(GateRef glue,
172                                                            GateRef receiver,
173                                                            GateRef key,
174                                                            GateRef value,
175                                                            GateRef profileTypeInfo,
176                                                            GateRef slotId,
177                                                            ProfileOperation callback)
178{
179    auto env = GetEnvironment();
180    Label entry(env);
181    env->SubCfgEntry(&entry);
182    Label exit(env);
183    Label tryFastPath(env);
184    Label slowPath(env);
185    Label tryPreDump(env);
186
187    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
188    ICStubBuilder builder(this);
189    builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, callback);
190    builder.StoreICByName(&result, &tryFastPath, &tryPreDump, &exit);
191    Bind(&tryFastPath);
192    {
193        result = SetPropertyByName(glue, receiver, key, value, false, True(), callback);
194        Branch(TaggedIsHole(*result), &slowPath, &exit);
195    }
196    Bind(&tryPreDump);
197    {
198        callback.TryPreDump();
199        Jump(&slowPath);
200    }
201    Bind(&slowPath);
202    {
203        result = CallRuntime(
204            glue, RTSTUB_ID(StoreICByName), {profileTypeInfo, receiver, key, value, IntToTaggedInt(slotId)});
205        Jump(&exit);
206    }
207
208    Bind(&exit);
209    auto ret = *result;
210    env->SubCfgExit();
211    return ret;
212}
213
214GateRef AccessObjectStubBuilder::ResolvePropKey(GateRef glue, GateRef prop, const StringIdInfo &info)
215{
216    if (jsFunc_ != Circuit::NullGate()) {
217        GateRef constpool = GetConstPoolFromFunction(jsFunc_);
218        return GetStringFromConstPool(glue, constpool, ChangeIntPtrToInt32(prop));
219    }
220    if (!info.IsValid()) {
221        return prop;
222    }
223    ASSERT(info.IsValid());
224    InterpreterToolsStubBuilder builder(GetCallSignature(), GetEnvironment());
225    GateRef stringId = builder.GetStringId(info);
226    return GetStringFromConstPool(glue, info.GetConstantPool(), stringId);
227}
228
229GateRef AccessObjectStubBuilder::LoadObjByValue(GateRef glue, GateRef receiver, GateRef key, GateRef profileTypeInfo,
230                                                GateRef slotId, ProfileOperation callback)
231{
232    auto env = GetEnvironment();
233    Label entry(env);
234    env->SubCfgEntry(&entry);
235    Label exit(env);
236    Label tryFastPath(env);
237    Label slowPath(env);
238    Label tryPreDump(env);
239
240    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
241    GateRef value = 0;
242    ICStubBuilder builder(this);
243    builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, key);
244    builder.LoadICByValue(&result, &tryFastPath, &tryPreDump, &exit, callback);
245    Bind(&tryFastPath);
246    {
247        result = GetPropertyByValue(glue, receiver, key, callback);
248        BRANCH(TaggedIsHole(*result), &slowPath, &exit);
249    }
250    Bind(&tryPreDump);
251    {
252        callback.TryPreDump();
253        Jump(&slowPath);
254    }
255    Bind(&slowPath);
256    {
257        result = CallRuntime(glue, RTSTUB_ID(LoadICByValue), {profileTypeInfo, receiver, key, IntToTaggedInt(slotId)});
258        Jump(&exit);
259    }
260    Bind(&exit);
261    auto ret = *result;
262    env->SubCfgExit();
263    return ret;
264}
265
266// Used for deprecated bytecodes which will not support ic
267GateRef AccessObjectStubBuilder::DeprecatedLoadObjByValue(GateRef glue, GateRef receiver, GateRef key)
268{
269    auto env = GetEnvironment();
270    Label entry(env);
271    env->SubCfgEntry(&entry);
272    Label exit(env);
273    Label fastPath(env);
274    Label slowPath(env);
275
276    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
277    BRANCH(TaggedIsHeapObject(receiver), &fastPath, &slowPath);
278    Bind(&fastPath);
279    {
280        result = GetPropertyByValue(glue, receiver, key, ProfileOperation());
281        BRANCH(TaggedIsHole(*result), &slowPath, &exit);
282    }
283    Bind(&slowPath);
284    {
285        result = CallRuntime(glue, RTSTUB_ID(LoadICByValue),
286            { Undefined(), receiver, key, IntToTaggedInt(Int32(0xFF)) });  // 0xFF: invalied slot id
287        Jump(&exit);
288    }
289    Bind(&exit);
290    auto ret = *result;
291    env->SubCfgExit();
292    return ret;
293}
294
295GateRef AccessObjectStubBuilder::StoreObjByValue(GateRef glue, GateRef receiver, GateRef key, GateRef value,
296                                                 GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
297{
298    auto env = GetEnvironment();
299    Label entry(env);
300    env->SubCfgEntry(&entry);
301    Label exit(env);
302    Label tryFastPath(env);
303    Label slowPath(env);
304    Label tryPreDump(env);
305
306    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
307    ICStubBuilder builder(this);
308    builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, key, callback);
309    builder.StoreICByValue(&result, &tryFastPath, &tryPreDump, &exit);
310    Bind(&tryFastPath);
311    {
312        result = SetPropertyByValue(glue, receiver, key, value, false, callback);
313        BRANCH(TaggedIsHole(*result), &slowPath, &exit);
314    }
315    Bind(&tryPreDump);
316    {
317        callback.TryPreDump();
318        Jump(&slowPath);
319    }
320    Bind(&slowPath);
321    {
322        result = CallRuntime(
323            glue, RTSTUB_ID(StoreICByValue), {profileTypeInfo, receiver, key, value, IntToTaggedInt(slotId)});
324        Jump(&exit);
325    }
326    Bind(&exit);
327    auto ret = *result;
328    env->SubCfgExit();
329    return ret;
330}
331
332GateRef AccessObjectStubBuilder::StoreOwnByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value,
333                                                 GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
334{
335    auto env = GetEnvironment();
336    Label entry(env);
337    env->SubCfgEntry(&entry);
338    Label exit(env);
339    Label tryFastPath(env);
340    Label slowPath(env);
341    Label tryPreDump(env);
342
343    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
344    ICStubBuilder builder(this);
345    builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, IntToTaggedPtr(index), callback);
346    builder.StoreICByValue(&result, &tryFastPath, &tryPreDump, &exit);
347    Bind(&tryFastPath);
348    {
349        Label isHeapObject(env);
350        BRANCH(TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
351        Bind(&isHeapObject);
352        Label notClassConstructor(env);
353        BRANCH(IsClassConstructor(receiver), &slowPath, &notClassConstructor);
354        Bind(&notClassConstructor);
355        Label notClassPrototype(env);
356        BRANCH(IsClassPrototype(receiver), &slowPath, &notClassPrototype);
357        Bind(&notClassPrototype);
358        result = SetPropertyByIndex(glue, receiver, index, value, true);
359        BRANCH(TaggedIsHole(*result), &slowPath, &exit);
360    }
361    Bind(&tryPreDump);
362    {
363        callback.TryPreDump();
364        Jump(&slowPath);
365    }
366    Bind(&slowPath);
367    {
368        result = CallRuntime(glue,
369                             RTSTUB_ID(StoreOwnICByValue),
370                             {profileTypeInfo, receiver, IntToTaggedInt(index), value, IntToTaggedInt(slotId)});
371        Jump(&exit);
372    }
373    Bind(&exit);
374    auto ret = *result;
375    env->SubCfgExit();
376    return ret;
377}
378
379GateRef AccessObjectStubBuilder::TryLoadGlobalByName(GateRef glue, GateRef prop, const StringIdInfo &info,
380                                                     GateRef profileTypeInfo, GateRef slotId,
381                                                     ProfileOperation callback)
382{
383    auto env = GetEnvironment();
384    Label entry(env);
385    env->SubCfgEntry(&entry);
386    Label exit(env);
387    Label tryFastPath(env);
388    Label slowPath(env);
389
390    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
391    GateRef receiver = 0;
392    GateRef value = 0;
393    ICStubBuilder builder(this);
394    builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
395    builder.TryLoadGlobalICByName(&result, &tryFastPath, &slowPath, &exit);
396    Bind(&tryFastPath);
397    {
398        GateRef propKey = ResolvePropKey(glue, prop, info);
399        GateRef record = LdGlobalRecord(glue, propKey);
400        Label foundInRecord(env);
401        Label notFoundInRecord(env);
402        BRANCH(TaggedIsUndefined(record), &notFoundInRecord, &foundInRecord);
403        Bind(&foundInRecord);
404        {
405            result = Load(VariableType::JS_ANY(), record, IntPtr(PropertyBox::VALUE_OFFSET));
406            Jump(&exit);
407        }
408        Bind(&notFoundInRecord);
409        {
410            GateRef globalObject = GetGlobalObject(glue);
411            result = GetGlobalOwnProperty(glue, globalObject, propKey, callback);
412            BRANCH(TaggedIsHole(*result), &slowPath, &exit);
413        }
414    }
415    Bind(&slowPath);
416    {
417        GateRef propKey = ResolvePropKey(glue, prop, info);
418        result = CallRuntime(glue, RTSTUB_ID(TryLdGlobalICByName),
419                             { profileTypeInfo, propKey, IntToTaggedInt(slotId) });
420        Jump(&exit);
421    }
422
423    Bind(&exit);
424    auto ret = *result;
425    env->SubCfgExit();
426    return ret;
427}
428
429GateRef AccessObjectStubBuilder::TryStoreGlobalByName(GateRef glue, GateRef prop, const StringIdInfo &info,
430                                                      GateRef value, GateRef profileTypeInfo, GateRef slotId,
431                                                      ProfileOperation callback)
432{
433    auto env = GetEnvironment();
434    Label entry(env);
435    env->SubCfgEntry(&entry);
436    Label exit(env);
437    Label tryFastPath(env);
438    Label slowPath(env);
439
440    DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
441    GateRef receiver = 0;
442    ICStubBuilder builder(this);
443    builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
444    builder.TryStoreGlobalICByName(&result, &tryFastPath, &slowPath, &exit);
445    Bind(&tryFastPath);
446    {
447        GateRef propKey = ResolvePropKey(glue, prop, info);
448        GateRef record = LdGlobalRecord(glue, propKey);
449        Label foundInRecord(env);
450        Label notFoundInRecord(env);
451        BRANCH(TaggedIsUndefined(record), &notFoundInRecord, &foundInRecord);
452        Bind(&foundInRecord);
453        {
454            result = CallRuntime(glue, RTSTUB_ID(TryUpdateGlobalRecord), { propKey, value });
455            Jump(&exit);
456        }
457        Bind(&notFoundInRecord);
458        {
459            GateRef globalObject = GetGlobalObject(glue);
460            result = GetGlobalOwnProperty(glue, globalObject, propKey, callback);
461            Label isFoundInGlobal(env);
462            Label notFoundInGlobal(env);
463            BRANCH(TaggedIsHole(*result), &notFoundInGlobal, &isFoundInGlobal);
464            Bind(&isFoundInGlobal);
465            {
466                result = CallRuntime(glue, RTSTUB_ID(StGlobalVar), { propKey, value });
467                Jump(&exit);
468            }
469            Bind(&notFoundInGlobal);
470            {
471                result = CallRuntime(glue, RTSTUB_ID(ThrowReferenceError), { propKey });
472                Jump(&exit);
473            }
474        }
475    }
476    Bind(&slowPath);
477    {
478        GateRef propKey = ResolvePropKey(glue, prop, info);
479        GateRef globalObject = GetGlobalObject(glue);
480        result = CallRuntime(glue, RTSTUB_ID(StoreMiss),
481                             { profileTypeInfo, globalObject, propKey, value, IntToTaggedInt(slotId),
482                               IntToTaggedInt(Int32(static_cast<int>(ICKind::NamedGlobalTryStoreIC))) });
483        Jump(&exit);
484    }
485
486    Bind(&exit);
487    auto ret = *result;
488    env->SubCfgExit();
489    return ret;
490}
491
492GateRef AccessObjectStubBuilder::LoadGlobalVar(GateRef glue, GateRef prop, const StringIdInfo &info,
493                                               GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
494{
495    auto env = GetEnvironment();
496    Label entry(env);
497    env->SubCfgEntry(&entry);
498    Label exit(env);
499    Label tryFastPath(env);
500    Label slowPath(env);
501
502    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
503    GateRef receiver = 0;
504    GateRef value = 0;
505    ICStubBuilder builder(this);
506    builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
507    builder.TryLoadGlobalICByName(&result, &tryFastPath, &slowPath, &exit);
508    Bind(&tryFastPath);
509    {
510        GateRef globalObject = GetGlobalObject(glue);
511        GateRef propKey = ResolvePropKey(glue, prop, info);
512        result = GetGlobalOwnProperty(glue, globalObject, propKey, callback);
513        BRANCH(TaggedIsHole(*result), &slowPath, &exit);
514    }
515    Bind(&slowPath);
516    {
517        GateRef globalObject = GetGlobalObject(glue);
518        GateRef propKey = ResolvePropKey(glue, prop, info);
519        result = CallRuntime(glue, RTSTUB_ID(LdGlobalICVar),
520                             { globalObject, propKey, profileTypeInfo, IntToTaggedInt(slotId) });
521        Jump(&exit);
522    }
523
524    Bind(&exit);
525    auto ret = *result;
526    env->SubCfgExit();
527    return ret;
528}
529
530GateRef AccessObjectStubBuilder::StoreGlobalVar(GateRef glue, GateRef prop, const StringIdInfo &info,
531                                                GateRef value, GateRef profileTypeInfo, GateRef slotId)
532{
533    auto env = GetEnvironment();
534    Label entry(env);
535    env->SubCfgEntry(&entry);
536    Label exit(env);
537    Label tryFastPath(env);
538    Label slowPath(env);
539
540    DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
541    GateRef receiver = 0;
542    ICStubBuilder builder(this);
543    builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
544    builder.TryStoreGlobalICByName(&result, &tryFastPath, &slowPath, &exit);
545    Bind(&tryFastPath);
546    {
547        GateRef propKey = ResolvePropKey(glue, prop, info);
548        // IR later
549        result = CallRuntime(glue, RTSTUB_ID(StGlobalVar), { propKey, value });
550        Jump(&exit);
551    }
552    Bind(&slowPath);
553    {
554        GateRef propKey = ResolvePropKey(glue, prop, info);
555        GateRef globalObject = GetGlobalObject(glue);
556        result = CallRuntime(glue, RTSTUB_ID(StoreMiss),
557                             { profileTypeInfo, globalObject, propKey, value, IntToTaggedInt(slotId),
558                               IntToTaggedInt(Int32(static_cast<int>(ICKind::NamedGlobalStoreIC))) });
559        Jump(&exit);
560    }
561
562    Bind(&exit);
563    auto ret = *result;
564    env->SubCfgExit();
565    return ret;
566}
567
568GateRef AccessObjectStubBuilder::StOwnByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value)
569{
570    auto env = GetEnvironment();
571    Label entry(env);
572    env->SubCfgEntry(&entry);
573    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
574    Label isHeapObject(env);
575    Label slowPath(env);
576    Label exit(env);
577    BRANCH(TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
578    Bind(&isHeapObject);
579    Label notClassConstructor(env);
580    BRANCH(IsClassConstructor(receiver), &slowPath, &notClassConstructor);
581    Bind(&notClassConstructor);
582    Label notClassPrototype(env);
583    BRANCH(IsClassPrototype(receiver), &slowPath, &notClassPrototype);
584    Bind(&notClassPrototype);
585    {
586        result = SetPropertyByIndex(glue, receiver, TruncInt64ToInt32(index), value, true);
587        BRANCH(TaggedIsHole(*result), &slowPath, &exit);
588    }
589    Bind(&slowPath);
590    {
591        result = CallRuntime(glue, RTSTUB_ID(StOwnByIndex), {receiver, IntToTaggedInt(index), value });
592        Jump(&exit);
593    }
594    Bind(&exit);
595    auto ret = *result;
596    env->SubCfgExit();
597    return ret;
598}
599
600GateRef AccessObjectStubBuilder::StOwnByValue(GateRef glue, GateRef receiver, GateRef key, GateRef value)
601{
602    auto env = GetEnvironment();
603    Label entry(env);
604    env->SubCfgEntry(&entry);
605    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
606    Label isHeapObject(env);
607    Label slowPath(env);
608    Label exit(env);
609    BRANCH(TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
610    Bind(&isHeapObject);
611    Label notClassConstructor(env);
612    BRANCH(IsClassConstructor(receiver), &slowPath, &notClassConstructor);
613    Bind(&notClassConstructor);
614    Label notClassPrototype(env);
615    BRANCH(IsClassPrototype(receiver), &slowPath, &notClassPrototype);
616    Bind(&notClassPrototype);
617    {
618        result = SetPropertyByValue(glue, receiver, key, value, true);
619        BRANCH(TaggedIsHole(*result), &slowPath, &exit);
620    }
621    Bind(&slowPath);
622    {
623        result = CallRuntime(glue, RTSTUB_ID(StOwnByValue), { receiver, key, value });
624        Jump(&exit);
625    }
626    Bind(&exit);
627    auto ret = *result;
628    env->SubCfgExit();
629    return ret;
630}
631
632GateRef AccessObjectStubBuilder::StOwnByName(GateRef glue, GateRef receiver, GateRef key, GateRef value)
633{
634    auto env = GetEnvironment();
635    Label entry(env);
636    env->SubCfgEntry(&entry);
637    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
638    Label isJSObject(env);
639    Label slowPath(env);
640    Label exit(env);
641    BRANCH(IsJSObject(receiver), &isJSObject, &slowPath);
642    Bind(&isJSObject);
643    Label notClassConstructor(env);
644    BRANCH(IsClassConstructor(receiver), &slowPath, &notClassConstructor);
645    Bind(&notClassConstructor);
646    Label notClassPrototype(env);
647    BRANCH(IsClassPrototype(receiver), &slowPath, &notClassPrototype);
648    Bind(&notClassPrototype);
649    {
650        result = SetPropertyByName(glue, receiver, key, value, true, True());
651        BRANCH(TaggedIsHole(*result), &slowPath, &exit);
652    }
653    Bind(&slowPath);
654    {
655        result = CallRuntime(glue, RTSTUB_ID(StOwnByName), { receiver, key, value });
656        Jump(&exit);
657    }
658    Bind(&exit);
659    auto ret = *result;
660    env->SubCfgExit();
661    return ret;
662}
663
664GateRef AccessObjectStubBuilder::StOwnByValueWithNameSet(GateRef glue, GateRef receiver, GateRef key, GateRef value)
665{
666    auto env = GetEnvironment();
667    Label entry(env);
668    env->SubCfgEntry(&entry);
669    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
670    Label isHeapObject(env);
671    Label slowPath(env);
672    Label notClassConstructor(env);
673    Label notClassPrototype(env);
674    Label notHole(env);
675    Label exit(env);
676    BRANCH(TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
677    Bind(&isHeapObject);
678    {
679        BRANCH(IsClassConstructor(receiver), &slowPath, &notClassConstructor);
680        Bind(&notClassConstructor);
681        {
682            BRANCH(IsClassPrototype(receiver), &slowPath, &notClassPrototype);
683            Bind(&notClassPrototype);
684            {
685                result = SetPropertyByValue(glue, receiver, key, value, true, ProfileOperation(), true);
686                BRANCH(TaggedIsHole(*result), &slowPath, &notHole);
687                Bind(&notHole);
688                {
689                    Label notexception(env);
690                    BRANCH(TaggedIsException(*result), &exit, &notexception);
691                    Bind(&notexception);
692                    CallRuntime(glue, RTSTUB_ID(SetFunctionNameNoPrefix), { value, key });
693                    Jump(&exit);
694                }
695            }
696        }
697    }
698    Bind(&slowPath);
699    {
700        result = CallRuntime(glue, RTSTUB_ID(StOwnByValueWithNameSet), { receiver, key, value });
701        Jump(&exit);
702    }
703    Bind(&exit);
704    auto ret = *result;
705    env->SubCfgExit();
706    return ret;
707}
708
709GateRef AccessObjectStubBuilder::StOwnByNameWithNameSet(GateRef glue, GateRef receiver, GateRef key, GateRef value)
710{
711    auto env = GetEnvironment();
712    Label entry(env);
713    env->SubCfgEntry(&entry);
714    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
715    Label isJSObject(env);
716    Label notJSObject(env);
717    Label notClassConstructor(env);
718    Label notClassPrototype(env);
719    Label notHole(env);
720    Label exit(env);
721    BRANCH(IsJSObject(receiver), &isJSObject, &notJSObject);
722    Bind(&isJSObject);
723    {
724        BRANCH(IsClassConstructor(receiver), &notJSObject, &notClassConstructor);
725        Bind(&notClassConstructor);
726        {
727            BRANCH(IsClassPrototype(receiver), &notJSObject, &notClassPrototype);
728            Bind(&notClassPrototype);
729            {
730                result = SetPropertyByName(glue, receiver, key, value, true, True(), ProfileOperation(), false, true);
731                BRANCH(TaggedIsHole(*result), &notJSObject, &notHole);
732                Bind(&notHole);
733                {
734                    Label notException(env);
735                    BRANCH(TaggedIsException(*result), &exit, &notException);
736                    Bind(&notException);
737                    CallRuntime(glue, RTSTUB_ID(SetFunctionNameNoPrefix), {value, key});
738                    Jump(&exit);
739                }
740            }
741        }
742    }
743    Bind(&notJSObject);
744    {
745        result = CallRuntime(glue, RTSTUB_ID(StOwnByNameWithNameSet), { receiver, key, value });
746        Jump(&exit);
747    }
748    Bind(&exit);
749    auto ret = *result;
750    env->SubCfgExit();
751    return ret;
752}
753
754GateRef AccessObjectStubBuilder::StObjByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value)
755{
756    auto env = GetEnvironment();
757    Label entry(env);
758    env->SubCfgEntry(&entry);
759    DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
760    Label exit(env);
761    Label fastPath(env);
762    Label slowPath(env);
763    BRANCH(TaggedIsHeapObject(receiver), &fastPath, &slowPath);
764    Bind(&fastPath);
765    {
766        result = SetPropertyByIndex(glue, receiver, TruncInt64ToInt32(index), value, false);
767        BRANCH(TaggedIsHole(*result), &slowPath, &exit);
768    }
769    Bind(&slowPath);
770    {
771        result = CallRuntime(glue, RTSTUB_ID(StObjByIndex), {receiver, IntToTaggedInt(index), value});
772        Jump(&exit);
773    }
774    Bind(&exit);
775    auto ret = *result;
776    env->SubCfgExit();
777    return ret;
778}
779
780GateRef AccessObjectStubBuilder::LdObjByIndex(GateRef glue, GateRef receiver, GateRef index)
781{
782    auto env = GetEnvironment();
783    Label entry(env);
784    env->SubCfgEntry(&entry);
785    DEFVARIABLE(varAcc, VariableType::JS_ANY(), Hole());
786    Label fastPath(env);
787    Label slowPath(env);
788    Label exit(env);
789    BRANCH(TaggedIsHeapObject(receiver), &fastPath, &slowPath);
790    Bind(&fastPath);
791    {
792        varAcc = GetPropertyByIndex(glue, receiver, TruncInt64ToInt32(index), ProfileOperation());
793        BRANCH(TaggedIsHole(*varAcc), &slowPath, &exit);
794    }
795    Bind(&slowPath);
796    {
797        GateRef undefined = Undefined();
798        auto args = { receiver, IntToTaggedInt(index), TaggedFalse(), undefined };
799        varAcc = CallRuntime(glue, RTSTUB_ID(LdObjByIndex), args);
800        Jump(&exit);
801    }
802    Bind(&exit);
803    auto ret = *varAcc;
804    env->SubCfgExit();
805    return ret;
806}
807}  // namespace panda::ecmascript::kungfu
808