1/*
2 * Copyright (c) 2023 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
16#include "ecmascript/compiler/builtins/builtins_function_stub_builder.h"
17
18#include "ecmascript/compiler/builtins/builtins_object_stub_builder.h"
19#include "ecmascript/compiler/call_stub_builder.h"
20#include "ecmascript/compiler/new_object_stub_builder.h"
21#include "ecmascript/compiler/stub_builder-inl.h"
22#include "ecmascript/js_arguments.h"
23
24namespace panda::ecmascript::kungfu {
25
26void BuiltinsFunctionStubBuilder::PrototypeApply(GateRef glue, GateRef thisValue,
27    GateRef numArgs, Variable* res, Label *exit, Label *slowPath)
28{
29    auto env = GetEnvironment();
30    Label targetIsCallable(env);
31    Label targetIsUndefined(env);
32    Label targetNotUndefined(env);
33    Label isHeapObject(env);
34    //1. If IsCallable(func) is false, throw a TypeError exception
35    BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
36    Bind(&isHeapObject);
37    {
38        BRANCH(IsCallable(thisValue), &targetIsCallable, slowPath);
39        Bind(&targetIsCallable);
40        {
41            GateRef thisArg = GetCallArg0(numArgs);
42            GateRef arrayObj = GetCallArg1(numArgs);
43            // 2. If argArray is null or undefined, then
44            BRANCH(TaggedIsUndefined(arrayObj), &targetIsUndefined, &targetNotUndefined);
45            Bind(&targetIsUndefined);
46            {
47                // a. Return Call(func, thisArg).
48                JSCallArgs callArgs(JSCallMode::CALL_GETTER);
49                callArgs.callGetterArgs = { thisArg };
50                CallStubBuilder callBuilder(this, glue, thisValue, Int32(0), 0, nullptr, Circuit::NullGate(), callArgs);
51                res->WriteVariable(callBuilder.JSCallDispatch());
52                Jump(exit);
53            }
54            Bind(&targetNotUndefined);
55            {
56                // 3. Let argList be CreateListFromArrayLike(argArray).
57                GateRef elements = BuildArgumentsListFastElements(glue, arrayObj);
58                Label targetIsHole(env);
59                Label targetNotHole(env);
60                BRANCH(TaggedIsHole(elements), &targetIsHole, &targetNotHole);
61                Bind(&targetIsHole);
62                {
63                    BuiltinsObjectStubBuilder objectStubBuilder(this);
64                    GateRef argList = objectStubBuilder.CreateListFromArrayLike(glue, arrayObj);
65                    // 4. ReturnIfAbrupt(argList).
66                    Label isPendingException(env);
67                    Label noPendingException(env);
68                    BRANCH(HasPendingException(glue), &isPendingException, &noPendingException);
69                    Bind(&isPendingException);
70                    {
71                        Jump(slowPath);
72                    }
73                    Bind(&noPendingException);
74                    {
75                        GateRef argsLength = GetLengthOfTaggedArray(argList);
76                        GateRef argv = PtrAdd(argList, IntPtr(TaggedArray::DATA_OFFSET));
77                        JSCallArgs callArgs(JSCallMode::CALL_THIS_ARGV_WITH_RETURN);
78                        callArgs.callThisArgvWithReturnArgs = { argsLength, argv, thisArg };
79                        CallStubBuilder callBuilder(this, glue, thisValue, argsLength, 0, nullptr, Circuit::NullGate(),
80                            callArgs);
81                        res->WriteVariable(callBuilder.JSCallDispatch());
82                        Jump(exit);
83                    }
84                }
85                Bind(&targetNotHole);
86                {
87                    // 6. Return Call(func, thisArg, argList).
88                    Label taggedIsStableJsArg(env);
89                    Label taggedNotStableJsArg(env);
90                    BRANCH(IsStableJSArguments(glue, arrayObj), &taggedIsStableJsArg, &taggedNotStableJsArg);
91                    Bind(&taggedIsStableJsArg);
92                    {
93                        GateRef hClass = LoadHClass(arrayObj);
94                        GateRef PropertyInlinedPropsOffset = IntPtr(JSArguments::LENGTH_INLINE_PROPERTY_INDEX);
95                        GateRef result = GetPropertyInlinedProps(arrayObj, hClass, PropertyInlinedPropsOffset);
96                        GateRef length = TaggedGetInt(result);
97                        GateRef argsLength = MakeArgListWithHole(glue, elements, length);
98                        GateRef elementArgv = PtrAdd(elements, IntPtr(TaggedArray::DATA_OFFSET));
99                        JSCallArgs callArgs(JSCallMode::CALL_THIS_ARGV_WITH_RETURN);
100                        callArgs.callThisArgvWithReturnArgs = { argsLength, elementArgv, thisArg };
101                        CallStubBuilder callBuilder(this, glue, thisValue, argsLength, 0, nullptr, Circuit::NullGate(),
102                            callArgs);
103                        res->WriteVariable(callBuilder.JSCallDispatch());
104                        Jump(exit);
105                    }
106                    Bind(&taggedNotStableJsArg);
107                    {
108                        GateRef length = GetArrayLength(arrayObj);
109                        GateRef argsLength = MakeArgListWithHole(glue, elements, length);
110                        GateRef elementArgv = PtrAdd(elements, IntPtr(TaggedArray::DATA_OFFSET));
111                        JSCallArgs callArgs(JSCallMode::CALL_THIS_ARGV_WITH_RETURN);
112                        callArgs.callThisArgvWithReturnArgs = { argsLength, elementArgv, thisArg };
113                        CallStubBuilder callBuilder(this, glue, thisValue, argsLength, 0, nullptr, Circuit::NullGate(),
114                            callArgs);
115                        res->WriteVariable(callBuilder.JSCallDispatch());
116                        Jump(exit);
117                    }
118                }
119            }
120        }
121    }
122}
123
124void BuiltinsFunctionStubBuilder::PrototypeBind(GateRef glue, GateRef thisValue,
125    GateRef numArgs, Variable* res, Label *exit, Label *slowPath)
126{
127    auto env = GetEnvironment();
128    Label targetIsHeapObject(env);
129    Label targetIsCallable(env);
130    Label targetIsJSFunctionOrBound(env);
131    Label targetNameAndLengthNotChange(env);
132
133    // 1. Let Target be the this value.
134    GateRef target = thisValue;
135    // 2. If IsCallable(Target) is false, throw a TypeError exception.
136    BRANCH(TaggedIsHeapObject(target), &targetIsHeapObject, slowPath);
137    Bind(&targetIsHeapObject);
138    BRANCH(IsCallable(target), &targetIsCallable, slowPath);
139    Bind(&targetIsCallable);
140    BRANCH(IsJSOrBoundFunction(target), &targetIsJSFunctionOrBound, slowPath);
141    Bind(&targetIsJSFunctionOrBound);
142    {
143        GateRef hclass = LoadHClass(target);
144        GateRef isTargetNameAndLengthNotChange = LogicAndBuilder(env)
145            .And(IntPtrEqual(GetPropertyInlinedProps(target, hclass, Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX)),
146                GetGlobalConstantValue(VariableType::JS_POINTER(), glue, ConstantIndex::FUNCTION_NAME_ACCESSOR)))
147            .And(IntPtrEqual(GetPropertyInlinedProps(target, hclass, Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX)),
148                GetGlobalConstantValue(VariableType::JS_POINTER(), glue, ConstantIndex::FUNCTION_LENGTH_ACCESSOR)))
149            .Done();
150        BRANCH(isTargetNameAndLengthNotChange, &targetNameAndLengthNotChange, slowPath);
151        Bind(&targetNameAndLengthNotChange);
152        {
153            Label numArgsMoreThan1(env);
154            Label createTaggedArray(env);
155            GateRef thisArg = GetCallArg0(numArgs);
156            DEFVARIABLE(argsLength, VariableType::INT32(), Int32(0));
157            BRANCH(Int64GreaterThan(numArgs, Int64(1)), &numArgsMoreThan1, &createTaggedArray);
158            Bind(&numArgsMoreThan1);
159            {
160                argsLength = Int32Sub(TruncInt64ToInt32(numArgs), Int32(1));
161                Jump(&createTaggedArray);
162            }
163            Bind(&createTaggedArray);
164            // 3. Let args be a new (possibly empty) List consisting of all of the argument
165            //    values provided after thisArg in order.
166            GateRef argsArray = NewTaggedArrayFromArgs(glue, Int32(1), *argsLength, numArgs);
167            // 4. Let F be BoundFunctionCreate(Target, thisArg, args).
168            NewObjectStubBuilder newBuilder(this);
169            GateRef boundFunction = newBuilder.NewJSBoundFunction(glue, target, thisArg, argsArray);
170            // use default name and length property because they are not changed
171            res->WriteVariable(boundFunction);
172            Jump(exit);
173        }
174    }
175}
176
177void BuiltinsFunctionStubBuilder::PrototypeCall(GateRef glue, GateRef thisValue,
178    GateRef numArgs, Variable* res, Label *exit, Label *slowPath)
179{
180    auto env = GetEnvironment();
181    Label funcIsHeapObject(env);
182    Label funcIsCallable(env);
183
184    // 1. If IsCallable(func) is false, throw a TypeError exception.
185    GateRef func = thisValue;
186    BRANCH(TaggedIsHeapObject(func), &funcIsHeapObject, slowPath);
187    Bind(&funcIsHeapObject);
188    BRANCH(IsCallable(func), &funcIsCallable, slowPath);
189    Bind(&funcIsCallable);
190    {
191        Label call0(env);
192        Label moreThan0(env);
193        Label call1(env);
194        Label moreThan1(env);
195        Label call2(env);
196        Label moreThan2(env);
197        Label createTaggedArray(env);
198        GateRef thisArg = GetCallArg0(numArgs);
199        // 2. Let argList be an empty List.
200        // 3. If this method was called with more than one argument then in left to right order,
201        //    starting with the second argument, append each argument as the last element of argList.
202        // 5. Return Call(func, thisArg, argList).
203        BRANCH(Int64LessThanOrEqual(numArgs, Int64(1)), &call0, &moreThan0);  // 1: thisArg
204        Bind(&call0);
205        {
206            JSCallArgs callArgs(JSCallMode::CALL_GETTER);
207            callArgs.callGetterArgs = { thisArg };
208            CallStubBuilder callBuilder(this, glue, func, Int32(0), 0, nullptr, Circuit::NullGate(), callArgs);
209            res->WriteVariable(callBuilder.JSCallDispatch());
210            Jump(exit);
211        }
212        Bind(&moreThan0);
213        BRANCH(Int64Equal(numArgs, Int64(2)), &call1, &moreThan1);  // 2: thisArg + 1 arg
214        Bind(&call1);
215        {
216            JSCallArgs callArgs(JSCallMode::CALL_SETTER);
217            callArgs.callSetterArgs = { thisArg, GetCallArg1(numArgs) };
218            CallStubBuilder callBuilder(this, glue, func, Int32(1), 0, nullptr, Circuit::NullGate(), callArgs);
219            res->WriteVariable(callBuilder.JSCallDispatch());
220            Jump(exit);
221        }
222        Bind(&moreThan1);
223        BRANCH(Int64Equal(numArgs, Int64(3)), &call2, &moreThan2);  // 3: thisArg + 2 args
224        Bind(&call2);
225        {
226            JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG2_WITH_RETURN);
227            callArgs.callThisArg2WithReturnArgs = { thisArg, GetCallArg1(numArgs), GetCallArg2(numArgs) };
228            CallStubBuilder callBuilder(this, glue, func, Int32(2), 0, nullptr, Circuit::NullGate(),  // 2: call 2
229                callArgs);
230            res->WriteVariable(callBuilder.JSCallDispatch());
231            Jump(exit);
232        }
233        Bind(&moreThan2);
234        {
235            // currently argv will not be used in builtins IR except constructor
236            GateRef argsLength = Int32Sub(TruncInt64ToInt32(numArgs), Int32(1));  // 1: thisArg
237            GateRef elementArgv = PtrAdd(GetArgv(), IntPtr(JSTaggedValue::TaggedTypeSize()));
238            JSCallArgs callArgs(JSCallMode::CALL_THIS_ARGV_WITH_RETURN);
239            callArgs.callThisArgvWithReturnArgs = { argsLength, elementArgv, thisArg };
240            CallStubBuilder callBuilder(this, glue, func, argsLength, 0, nullptr, Circuit::NullGate(), callArgs);
241            res->WriteVariable(callBuilder.JSCallDispatch());
242            Jump(exit);
243        }
244    }
245}
246
247// return elements
248GateRef BuiltinsFunctionStubBuilder::BuildArgumentsListFastElements(GateRef glue, GateRef arrayObj)
249{
250    auto env = GetEnvironment();
251    Label subentry(env);
252    env->SubCfgEntry(&subentry);
253    DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
254    Label exit(env);
255    Label hasStableElements(env);
256    Label targetIsStableJSArguments(env);
257    Label targetNotStableJSArguments(env);
258    Label targetIsInt(env);
259    Label hClassEqual(env);
260    Label targetIsStableJSArray(env);
261    Label targetNotStableJSArray(env);
262
263    BRANCH(HasStableElements(glue, arrayObj), &hasStableElements, &exit);
264    Bind(&hasStableElements);
265    {
266        BRANCH(IsStableJSArguments(glue, arrayObj), &targetIsStableJSArguments, &targetNotStableJSArguments);
267        Bind(&targetIsStableJSArguments);
268        {
269            GateRef hClass = LoadHClass(arrayObj);
270            GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
271            GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
272            GateRef argmentsClass = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
273                                                      GlobalEnv::ARGUMENTS_CLASS);
274            BRANCH(Int64Equal(hClass, argmentsClass), &hClassEqual, &exit);
275            Bind(&hClassEqual);
276            {
277                GateRef PropertyInlinedPropsOffset = IntPtr(JSArguments::LENGTH_INLINE_PROPERTY_INDEX);
278                GateRef result = GetPropertyInlinedProps(arrayObj, hClass, PropertyInlinedPropsOffset);
279                BRANCH(TaggedIsInt(result), &targetIsInt, &exit);
280                Bind(&targetIsInt);
281                {
282                    res = GetElementsArray(arrayObj);
283                    Label isMutantTaggedArray(env);
284                    BRANCH(IsMutantTaggedArray(*res), &isMutantTaggedArray, &exit);
285                    Bind(&isMutantTaggedArray);
286                    {
287                        NewObjectStubBuilder newBuilder(this);
288                        GateRef elementsLength = GetLengthOfTaggedArray(*res);
289                        GateRef newTaggedArgList = newBuilder.NewTaggedArray(glue, elementsLength);
290                        DEFVARIABLE(index, VariableType::INT32(), Int32(0));
291                        Label loopHead(env);
292                        Label loopEnd(env);
293                        Label afterLoop(env);
294                        Label storeValue(env);
295                        Jump(&loopHead);
296                        LoopBegin(&loopHead);
297                        {
298                            BRANCH(Int32UnsignedLessThan(*index, elementsLength), &storeValue, &afterLoop);
299                            Bind(&storeValue);
300                            {
301                                GateRef value = GetTaggedValueWithElementsKind(arrayObj, *index);
302                                SetValueToTaggedArray(VariableType::JS_ANY(), glue, newTaggedArgList, *index, value);
303                                index = Int32Add(*index, Int32(1));
304                                Jump(&loopEnd);
305                            }
306                        }
307                        Bind(&loopEnd);
308                        LoopEnd(&loopHead);
309                        Bind(&afterLoop);
310                        {
311                            res = newTaggedArgList;
312                            Jump(&exit);
313                        }
314                    }
315                }
316            }
317        }
318        Bind(&targetNotStableJSArguments);
319        {
320            BRANCH(IsStableJSArray(glue, arrayObj), &targetIsStableJSArray, &targetNotStableJSArray);
321            Bind(&targetIsStableJSArray);
322            {
323                res = GetElementsArray(arrayObj);
324                Label isMutantTaggedArray(env);
325                BRANCH(IsMutantTaggedArray(*res), &isMutantTaggedArray, &exit);
326                Bind(&isMutantTaggedArray);
327                {
328                    NewObjectStubBuilder newBuilder(this);
329                    GateRef elementsLength = GetLengthOfTaggedArray(*res);
330                    GateRef newTaggedArgList = newBuilder.NewTaggedArray(glue, elementsLength);
331                    DEFVARIABLE(index, VariableType::INT32(), Int32(0));
332                    Label loopHead(env);
333                    Label loopEnd(env);
334                    Label afterLoop(env);
335                    Label storeValue(env);
336                    Jump(&loopHead);
337                    LoopBegin(&loopHead);
338                    {
339                        BRANCH(Int32UnsignedLessThan(*index, elementsLength), &storeValue, &afterLoop);
340                        Bind(&storeValue);
341                        {
342                            GateRef value = GetTaggedValueWithElementsKind(arrayObj, *index);
343                            SetValueToTaggedArray(VariableType::JS_ANY(), glue, newTaggedArgList, *index, value);
344                            index = Int32Add(*index, Int32(1));
345                            Jump(&loopEnd);
346                        }
347                    }
348                    Bind(&loopEnd);
349                    LoopEnd(&loopHead);
350                    Bind(&afterLoop);
351                    {
352                        res = newTaggedArgList;
353                        Jump(&exit);
354                    }
355                }
356            }
357            Bind(&targetNotStableJSArray);
358            {
359                FatalPrint(glue, { Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable)) });
360                Jump(&exit);
361            }
362        }
363    }
364    Bind(&exit);
365    auto ret = *res;
366    env->SubCfgExit();
367    return ret;
368}
369
370GateRef BuiltinsFunctionStubBuilder::MakeArgListWithHole(GateRef glue, GateRef argv, GateRef length)
371{
372    auto env = GetEnvironment();
373    Label subentry(env);
374    env->SubCfgEntry(&subentry);
375    DEFVARIABLE(res, VariableType::INT32(), length);
376    DEFVARIABLE(i, VariableType::INT32(), Int32(0));
377    Label exit(env);
378    Label greatThanZero(env);
379    Label lessThanZero(env);
380    BRANCH(Int32GreaterThan(length, Int32(0)), &greatThanZero, &lessThanZero);
381    Bind(&lessThanZero);
382    {
383        res = Int32(0);
384        Jump(&exit);
385    }
386    Bind(&greatThanZero);
387    GateRef argsLength = GetLengthOfTaggedArray(argv);
388    Label lengthGreaterThanArgsLength(env);
389    Label lengthLessThanArgsLength(env);
390    BRANCH(Int32GreaterThan(length, argsLength), &lengthGreaterThanArgsLength, &lengthLessThanArgsLength);
391    Bind(&lengthGreaterThanArgsLength);
392    {
393        res = argsLength;
394        Jump(&lengthLessThanArgsLength);
395    }
396    Bind(&lengthLessThanArgsLength);
397    {
398        Label loopHead(env);
399        Label loopEnd(env);
400        Label targetIsHole(env);
401        Label targetNotHole(env);
402        BRANCH(Int32UnsignedLessThan(*i, *res), &loopHead, &exit);
403        LoopBegin(&loopHead);
404        {
405            GateRef value = GetValueFromTaggedArray(argv, *i);
406            BRANCH(TaggedIsHole(value), &targetIsHole, &targetNotHole);
407            Bind(&targetIsHole);
408            {
409                SetValueToTaggedArray(VariableType::JS_ANY(), glue, argv, *i, Undefined());
410                Jump(&targetNotHole);
411            }
412            Bind(&targetNotHole);
413            i = Int32Add(*i, Int32(1));
414            BRANCH(Int32UnsignedLessThan(*i, *res), &loopEnd, &exit);
415        }
416        Bind(&loopEnd);
417        LoopEnd(&loopHead);
418    }
419    Bind(&exit);
420    auto ret = *res;
421    env->SubCfgExit();
422    return ret;
423}
424
425GateRef BuiltinsFunctionStubBuilder::NewTaggedArrayFromArgs(GateRef glue, GateRef startIndex, GateRef length,
426                                                            GateRef numArgs)
427{
428    auto env = GetEnvironment();
429    Label subentry(env);
430    env->SubCfgEntry(&subentry);
431
432    DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
433    DEFVARIABLE(i, VariableType::INT32(), Int32(0));
434    DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
435    NewObjectStubBuilder newBuilder(this);
436    res = newBuilder.NewTaggedArray(glue, length);
437    Label loopHead(env);
438    Label loopEnd(env);
439    Label afterLoop(env);
440    BRANCH(Int32LessThan(*i, length), &loopHead, &afterLoop);
441    LoopBegin(&loopHead);
442    {
443        Label valueArg0(env);
444        Label valueNotArg0(env);
445        Label valueArg1(env);
446        Label valueNotArg1(env);
447        Label valueArg2(env);
448        Label valueNotArg2(env);
449        Label valueSet(env);
450        GateRef index = Int32Add(*i, startIndex);
451        BRANCH(Int32Equal(index, Int32(0)), &valueArg0, &valueNotArg0);  // 0: get arg0
452        Bind(&valueArg0);
453        {
454            value = GetCallArg0(numArgs);
455            Jump(&valueSet);
456        }
457        Bind(&valueNotArg0);
458        BRANCH(Int32Equal(index, Int32(1)), &valueArg1, &valueNotArg1);  // 1: get arg1
459        Bind(&valueArg1);
460        {
461            value = GetCallArg1(numArgs);
462            Jump(&valueSet);
463        }
464        Bind(&valueNotArg1);
465        BRANCH(Int32Equal(index, Int32(2)), &valueArg2, &valueNotArg2);  // 2: get arg2
466        Bind(&valueArg2);
467        {
468            value = GetCallArg2(numArgs);
469            Jump(&valueSet);
470        }
471        Bind(&valueNotArg2);
472        {
473            // currently argv will not be used in builtins IR except constructor
474            value = GetArgFromArgv(ZExtInt32ToPtr(index));
475            Jump(&valueSet);
476        }
477        Bind(&valueSet);
478        SetValueToTaggedArray(VariableType::JS_ANY(), glue, *res, *i, *value);
479        i = Int32Add(*i, Int32(1));
480        BRANCH(Int32LessThan(*i, length), &loopEnd, &afterLoop);
481    }
482    Bind(&loopEnd);
483    LoopEnd(&loopHead);
484
485    Bind(&afterLoop);
486    auto ret = *res;
487    env->SubCfgExit();
488    return ret;
489}
490
491void BuiltinsFunctionStubBuilder::InitializeSFunction(GateRef glue, GateRef func, GateRef kind, FunctionKind getKind)
492{
493    auto env = GetEnvironment();
494    Label entry(env);
495    env->SubCfgEntry(&entry);
496    Label exit(env);
497    Label hasAccessOrIsBaseConstructor(env);
498    Label isBaseConstructor(env);
499    Label isNotBaseConstructor(env);
500
501    DEFVARIABLE(thisObj, VariableType::JS_ANY(), Undefined());
502    GateRef hclass = LoadHClass(func);
503
504    if (JSFunction::IsNormalFunctionAndCanSkipWbWhenInitialization(getKind)) {
505        SetProtoOrHClassToFunction(glue, func, Hole(), MemoryAttribute::NoBarrier());
506        SetWorkNodePointerToFunction(glue, func, NullPtr(), MemoryAttribute::NoBarrier());
507        SetProtoTransRootHClassToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
508        if (JSFunction::HasAccessor(getKind)) {
509            auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
510                                                       ConstantIndex::FUNCTION_NAME_ACCESSOR);
511            SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX),
512                                    VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
513            funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
514                                                  ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
515            SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX),
516                                    VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
517            Jump(&exit);
518        }
519    } else {
520        SetLexicalEnvToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
521        SetHomeObjectToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
522        SetProtoOrHClassToFunction(glue, func, Hole(), MemoryAttribute::NoBarrier());
523        SetProtoTransRootHClassToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
524        SetWorkNodePointerToFunction(glue, func, NullPtr(), MemoryAttribute::NoBarrier());
525        SetMethodToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
526
527        BRANCH(BitOr(HasAccessor(kind), IsBaseConstructorKind(kind)), &hasAccessOrIsBaseConstructor, &exit);
528        Bind(&hasAccessOrIsBaseConstructor);
529        {
530            Branch(IsBaseConstructorKind(kind), &isBaseConstructor, &isNotBaseConstructor);
531            Bind(&isBaseConstructor);
532            {
533                auto funcprotoAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
534                                                                ConstantIndex::FUNCTION_PROTOTYPE_ACCESSOR);
535                SetPropertyInlinedProps(glue, func, hclass, funcprotoAccessor,
536                                        Int32(JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX),
537                                        VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
538                Jump(&isNotBaseConstructor);
539            }
540            Bind(&isNotBaseConstructor);
541            auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
542                                                       ConstantIndex::FUNCTION_NAME_ACCESSOR);
543            SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
544                                    Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX),
545                                    VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
546            funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
547                                                  ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
548            SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
549                                    Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX),
550                                    VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
551            Jump(&exit);
552        }
553    }
554    Bind(&exit);
555    auto emptyProfileTypeInfoCell = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
556                                                           ConstantIndex::EMPTY_PROFILE_TYPE_INFO_CELL_INDEX);
557    SetRawProfileTypeInfoToFunction(glue, func, emptyProfileTypeInfoCell);
558    env->SubCfgExit();
559    return;
560}
561
562void BuiltinsFunctionStubBuilder::InitializeJSFunction(GateRef glue, GateRef func, GateRef kind, FunctionKind getKind)
563{
564    auto env = GetEnvironment();
565    Label entry(env);
566    env->SubCfgEntry(&entry);
567    Label exit(env);
568    Label hasProto(env);
569    Label notProto(env);
570    Label hasAccess(env);
571    Label isBase(env);
572    Label notBase(env);
573    Label isGenerator(env);
574    Label notClassConstructor(env);
575
576    DEFVARIABLE(thisObj, VariableType::JS_ANY(), Undefined());
577    GateRef hclass = LoadHClass(func);
578
579    if (JSFunction::IsNormalFunctionAndCanSkipWbWhenInitialization(getKind)) {
580        SetProtoOrHClassToFunction(glue, func, Hole(), MemoryAttribute::NoBarrier());
581        SetWorkNodePointerToFunction(glue, func, NullPtr(), MemoryAttribute::NoBarrier());
582        SetProtoTransRootHClassToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
583        if (JSFunction::HasPrototype(getKind)) {
584            auto funcprotoAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
585                                                            ConstantIndex::FUNCTION_PROTOTYPE_ACCESSOR);
586            if (getKind == FunctionKind::BASE_CONSTRUCTOR || getKind == FunctionKind::GENERATOR_FUNCTION ||
587                getKind == FunctionKind::ASYNC_GENERATOR_FUNCTION) {
588                SetPropertyInlinedProps(glue, func, hclass, funcprotoAccessor,
589                                        Int32(JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX),
590                                        VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
591                auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
592                                                           ConstantIndex::FUNCTION_NAME_ACCESSOR);
593                SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
594                                        Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX), VariableType::JS_ANY(),
595                                        MemoryAttribute::NoBarrier());
596                funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
597                                                      ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
598                SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
599                                        Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX), VariableType::JS_ANY(),
600                                        MemoryAttribute::NoBarrier());
601                if (getKind != FunctionKind::BASE_CONSTRUCTOR) {
602                    thisObj = CallRuntime(glue, RTSTUB_ID(InitializeGeneratorFunction), {kind});
603                    SetProtoOrHClassToFunction(glue, func, *thisObj);
604                }
605            } else if (!JSFunction::IsClassConstructor(getKind)) {
606                CallRuntime(glue, RTSTUB_ID(FunctionDefineOwnProperty), {func, funcprotoAccessor, kind});
607            }
608            Jump(&exit);
609        } else if (JSFunction::HasAccessor(getKind)) {
610            auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
611                                                       ConstantIndex::FUNCTION_NAME_ACCESSOR);
612            SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX),
613                                    VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
614            funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
615                                                  ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
616            SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX),
617                                    VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
618            Jump(&exit);
619        }
620    } else {
621        SetLexicalEnvToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
622        SetHomeObjectToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
623        SetProtoOrHClassToFunction(glue, func, Hole(), MemoryAttribute::NoBarrier());
624        SetProtoTransRootHClassToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
625        SetWorkNodePointerToFunction(glue, func, NullPtr(), MemoryAttribute::NoBarrier());
626        SetMethodToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
627
628        BRANCH(HasPrototype(kind), &hasProto, &notProto);
629        Bind(&hasProto);
630        {
631            auto funcprotoAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
632                                                            ConstantIndex::FUNCTION_PROTOTYPE_ACCESSOR);
633            BRANCH(IsBaseKind(kind), &isBase, &notBase);
634            Bind(&isBase);
635            {
636                SetPropertyInlinedProps(glue, func, hclass, funcprotoAccessor,
637                                        Int32(JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX),
638                                        VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
639                auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
640                                                           ConstantIndex::FUNCTION_NAME_ACCESSOR);
641                SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
642                                        Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX), VariableType::JS_ANY(),
643                                        MemoryAttribute::NoBarrier());
644                funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
645                                                      ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
646                SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
647                                        Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX), VariableType::JS_ANY(),
648                                        MemoryAttribute::NoBarrier());
649                BRANCH(IsGeneratorKind(kind), &isGenerator, &exit);
650                Bind(&isGenerator);
651                {
652                    thisObj = CallRuntime(glue, RTSTUB_ID(InitializeGeneratorFunction), {kind});
653                    SetProtoOrHClassToFunction(glue, func, *thisObj);
654                    Jump(&exit);
655                }
656            }
657            Bind(&notBase);
658            {
659                BRANCH(IsClassConstructorKind(kind), &exit, &notClassConstructor);
660                Bind(&notClassConstructor);
661                {
662                    CallRuntime(glue, RTSTUB_ID(FunctionDefineOwnProperty), {func, funcprotoAccessor, kind});
663                    Jump(&exit);
664                }
665            }
666        }
667        Bind(&notProto);
668        {
669            BRANCH(HasAccessor(kind), &hasAccess, &exit);
670            Bind(&hasAccess);
671            {
672                auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
673                                                           ConstantIndex::FUNCTION_NAME_ACCESSOR);
674                SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX),
675                                        VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
676                funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
677                                                      ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
678                SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
679                                        Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX),
680                                        VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
681                Jump(&exit);
682            }
683        }
684    }
685    Bind(&exit);
686    auto emptyProfileTypeInfoCell = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
687                                                           ConstantIndex::EMPTY_PROFILE_TYPE_INFO_CELL_INDEX);
688    SetRawProfileTypeInfoToFunction(glue, func, emptyProfileTypeInfoCell);
689    env->SubCfgExit();
690    return;
691}
692
693void BuiltinsFunctionStubBuilder::InitializeFunctionWithMethod(GateRef glue,
694    GateRef func, GateRef method, GateRef hclass)
695{
696    auto env = GetEnvironment();
697    Label entry(env);
698    env->SubCfgEntry(&entry);
699    Label exit(env);
700
701    SetCallableToBitfield(glue, hclass, true);
702    SetMethodToFunction(glue, func, method);
703
704    SetBitFieldToFunction(glue, func, Int32(0));
705    SetMachineCodeToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
706
707    Label hasCompiledStatus(env);
708    Label tryInitFuncCodeEntry(env);
709    BRANCH(IsAotWithCallField(method), &hasCompiledStatus, &tryInitFuncCodeEntry);
710    Bind(&hasCompiledStatus);
711    {
712        SetCompiledCodeFlagToFunctionFromMethod(glue, func, method);
713        Jump(&tryInitFuncCodeEntry);
714    }
715    // Notice: we set code entries for all function to deal with these situations
716    // 1) AOT compiled method, set AOT compiled code entry
717    // 2) define func with the deopted method, set the AOTToAsmInterpBridge
718    Bind(&tryInitFuncCodeEntry);
719    {
720        SetCodeEntryToFunctionFromMethod(glue, func, method);
721        Jump(&exit);
722    }
723
724    Bind(&exit);
725    env->SubCfgExit();
726    return;
727}
728}  // namespace panda::ecmascript::kungfu
729