• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
24 namespace panda::ecmascript::kungfu {
25 
PrototypeApply(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)26 void 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 
PrototypeBind(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)124 void 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 
PrototypeCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)177 void 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
BuildArgumentsListFastElements(GateRef glue,GateRef arrayObj)248 GateRef 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                 NewObjectStubBuilder newBuilder(this);
325                 GateRef elementsLength = GetLengthOfTaggedArray(*res);
326                 GateRef newTaggedArgList = newBuilder.NewTaggedArray(glue, elementsLength);
327                 DEFVARIABLE(index, VariableType::INT32(), Int32(0));
328                 Label loopHead(env);
329                 Label loopEnd(env);
330                 Label afterLoop(env);
331                 Label storeValue(env);
332                 Jump(&loopHead);
333                 LoopBegin(&loopHead);
334                 {
335                     BRANCH(Int32UnsignedLessThan(*index, elementsLength), &storeValue, &afterLoop);
336                     Bind(&storeValue);
337                     {
338                         GateRef value = GetTaggedValueWithElementsKind(arrayObj, *index);
339                         SetValueToTaggedArray(VariableType::JS_ANY(), glue, newTaggedArgList, *index, value);
340                         index = Int32Add(*index, Int32(1));
341                         Jump(&loopEnd);
342                     }
343                 }
344                 Bind(&loopEnd);
345                 LoopEnd(&loopHead);
346                 Bind(&afterLoop);
347                 {
348                     res = newTaggedArgList;
349                     Jump(&exit);
350                 }
351             }
352             Bind(&targetNotStableJSArray);
353             {
354                 FatalPrint(glue, { Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable)) });
355                 Jump(&exit);
356             }
357         }
358     }
359     Bind(&exit);
360     auto ret = *res;
361     env->SubCfgExit();
362     return ret;
363 }
364 
MakeArgListWithHole(GateRef glue,GateRef argv,GateRef length)365 GateRef BuiltinsFunctionStubBuilder::MakeArgListWithHole(GateRef glue, GateRef argv, GateRef length)
366 {
367     auto env = GetEnvironment();
368     Label subentry(env);
369     env->SubCfgEntry(&subentry);
370     DEFVARIABLE(res, VariableType::INT32(), length);
371     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
372     Label exit(env);
373     Label greatThanZero(env);
374     Label lessThanZero(env);
375     BRANCH(Int32GreaterThan(length, Int32(0)), &greatThanZero, &lessThanZero);
376     Bind(&lessThanZero);
377     {
378         res = Int32(0);
379         Jump(&exit);
380     }
381     Bind(&greatThanZero);
382     GateRef argsLength = GetLengthOfTaggedArray(argv);
383     Label lengthGreaterThanArgsLength(env);
384     Label lengthLessThanArgsLength(env);
385     BRANCH(Int32GreaterThan(length, argsLength), &lengthGreaterThanArgsLength, &lengthLessThanArgsLength);
386     Bind(&lengthGreaterThanArgsLength);
387     {
388         res = argsLength;
389         Jump(&lengthLessThanArgsLength);
390     }
391     Bind(&lengthLessThanArgsLength);
392     {
393         Label loopHead(env);
394         Label loopEnd(env);
395         Label targetIsHole(env);
396         Label targetNotHole(env);
397         BRANCH(Int32UnsignedLessThan(*i, *res), &loopHead, &exit);
398         LoopBegin(&loopHead);
399         {
400             GateRef value = GetValueFromTaggedArray(argv, *i);
401             BRANCH(TaggedIsHole(value), &targetIsHole, &targetNotHole);
402             Bind(&targetIsHole);
403             {
404                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, argv, *i, Undefined());
405                 Jump(&targetNotHole);
406             }
407             Bind(&targetNotHole);
408             i = Int32Add(*i, Int32(1));
409             BRANCH(Int32UnsignedLessThan(*i, *res), &loopEnd, &exit);
410         }
411         Bind(&loopEnd);
412         LoopEnd(&loopHead);
413     }
414     Bind(&exit);
415     auto ret = *res;
416     env->SubCfgExit();
417     return ret;
418 }
419 
NewTaggedArrayFromArgs(GateRef glue,GateRef startIndex,GateRef length,GateRef numArgs)420 GateRef BuiltinsFunctionStubBuilder::NewTaggedArrayFromArgs(GateRef glue, GateRef startIndex, GateRef length,
421                                                             GateRef numArgs)
422 {
423     auto env = GetEnvironment();
424     Label subentry(env);
425     env->SubCfgEntry(&subentry);
426 
427     DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
428     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
429     DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
430     NewObjectStubBuilder newBuilder(this);
431     res = newBuilder.NewTaggedArray(glue, length);
432     Label loopHead(env);
433     Label loopEnd(env);
434     Label afterLoop(env);
435     BRANCH(Int32LessThan(*i, length), &loopHead, &afterLoop);
436     LoopBegin(&loopHead);
437     {
438         Label valueArg0(env);
439         Label valueNotArg0(env);
440         Label valueArg1(env);
441         Label valueNotArg1(env);
442         Label valueArg2(env);
443         Label valueNotArg2(env);
444         Label valueSet(env);
445         GateRef index = Int32Add(*i, startIndex);
446         BRANCH(Int32Equal(index, Int32(0)), &valueArg0, &valueNotArg0);  // 0: get arg0
447         Bind(&valueArg0);
448         {
449             value = GetCallArg0(numArgs);
450             Jump(&valueSet);
451         }
452         Bind(&valueNotArg0);
453         BRANCH(Int32Equal(index, Int32(1)), &valueArg1, &valueNotArg1);  // 1: get arg1
454         Bind(&valueArg1);
455         {
456             value = GetCallArg1(numArgs);
457             Jump(&valueSet);
458         }
459         Bind(&valueNotArg1);
460         BRANCH(Int32Equal(index, Int32(2)), &valueArg2, &valueNotArg2);  // 2: get arg2
461         Bind(&valueArg2);
462         {
463             value = GetCallArg2(numArgs);
464             Jump(&valueSet);
465         }
466         Bind(&valueNotArg2);
467         {
468             // currently argv will not be used in builtins IR except constructor
469             value = GetArgFromArgv(ZExtInt32ToPtr(index));
470             Jump(&valueSet);
471         }
472         Bind(&valueSet);
473         SetValueToTaggedArray(VariableType::JS_ANY(), glue, *res, *i, *value);
474         i = Int32Add(*i, Int32(1));
475         BRANCH(Int32LessThan(*i, length), &loopEnd, &afterLoop);
476     }
477     Bind(&loopEnd);
478     LoopEnd(&loopHead);
479 
480     Bind(&afterLoop);
481     auto ret = *res;
482     env->SubCfgExit();
483     return ret;
484 }
485 
InitializeSFunction(GateRef glue,GateRef func,GateRef kind,FunctionKind getKind)486 void BuiltinsFunctionStubBuilder::InitializeSFunction(GateRef glue, GateRef func, GateRef kind, FunctionKind getKind)
487 {
488     auto env = GetEnvironment();
489     Label entry(env);
490     env->SubCfgEntry(&entry);
491     Label exit(env);
492     Label hasAccessOrIsBaseConstructor(env);
493     Label isBaseConstructor(env);
494     Label isNotBaseConstructor(env);
495 
496     DEFVARIABLE(thisObj, VariableType::JS_ANY(), Undefined());
497     GateRef hclass = LoadHClass(func);
498 
499     if (JSFunction::IsNormalFunctionAndCanSkipWbWhenInitialization(getKind)) {
500         SetProtoOrHClassToFunction(glue, func, Hole(), MemoryAttribute::NoBarrier());
501         SetWorkNodePointerToFunction(glue, func, NullPtr(), MemoryAttribute::NoBarrier());
502         SetProtoTransRootHClassToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
503         if (JSFunction::HasAccessor(getKind)) {
504             auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
505                                                        ConstantIndex::FUNCTION_NAME_ACCESSOR);
506             SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX),
507                                     VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
508             funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
509                                                   ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
510             SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX),
511                                     VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
512             Jump(&exit);
513         }
514     } else {
515         SetLexicalEnvToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
516         SetHomeObjectToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
517         SetProtoOrHClassToFunction(glue, func, Hole(), MemoryAttribute::NoBarrier());
518         SetProtoTransRootHClassToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
519         SetWorkNodePointerToFunction(glue, func, NullPtr(), MemoryAttribute::NoBarrier());
520         SetMethodToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
521 
522         BRANCH(BitOr(HasAccessor(kind), IsBaseConstructorKind(kind)), &hasAccessOrIsBaseConstructor, &exit);
523         Bind(&hasAccessOrIsBaseConstructor);
524         {
525             Branch(IsBaseConstructorKind(kind), &isBaseConstructor, &isNotBaseConstructor);
526             Bind(&isBaseConstructor);
527             {
528                 auto funcprotoAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
529                                                                 ConstantIndex::FUNCTION_PROTOTYPE_ACCESSOR);
530                 SetPropertyInlinedProps(glue, func, hclass, funcprotoAccessor,
531                                         Int32(JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX),
532                                         VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
533                 Jump(&isNotBaseConstructor);
534             }
535             Bind(&isNotBaseConstructor);
536             auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
537                                                        ConstantIndex::FUNCTION_NAME_ACCESSOR);
538             SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
539                                     Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX),
540                                     VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
541             funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
542                                                   ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
543             SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
544                                     Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX),
545                                     VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
546             Jump(&exit);
547         }
548     }
549     Bind(&exit);
550     auto emptyProfileTypeInfoCell = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
551                                                            ConstantIndex::EMPTY_PROFILE_TYPE_INFO_CELL_INDEX);
552     SetRawProfileTypeInfoToFunction(glue, func, emptyProfileTypeInfoCell);
553     env->SubCfgExit();
554     return;
555 }
556 
InitializeJSFunction(GateRef glue,GateRef func,GateRef kind,FunctionKind getKind)557 void BuiltinsFunctionStubBuilder::InitializeJSFunction(GateRef glue, GateRef func, GateRef kind, FunctionKind getKind)
558 {
559     auto env = GetEnvironment();
560     Label entry(env);
561     env->SubCfgEntry(&entry);
562     Label exit(env);
563     Label hasProto(env);
564     Label notProto(env);
565     Label hasAccess(env);
566     Label isBase(env);
567     Label notBase(env);
568     Label isGenerator(env);
569     Label notClassConstructor(env);
570 
571     DEFVARIABLE(thisObj, VariableType::JS_ANY(), Undefined());
572     GateRef hclass = LoadHClass(func);
573 
574     if (JSFunction::IsNormalFunctionAndCanSkipWbWhenInitialization(getKind)) {
575         SetProtoOrHClassToFunction(glue, func, Hole(), MemoryAttribute::NoBarrier());
576         SetWorkNodePointerToFunction(glue, func, NullPtr(), MemoryAttribute::NoBarrier());
577         SetProtoTransRootHClassToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
578         if (JSFunction::HasPrototype(getKind)) {
579             auto funcprotoAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
580                                                             ConstantIndex::FUNCTION_PROTOTYPE_ACCESSOR);
581             if (getKind == FunctionKind::BASE_CONSTRUCTOR || getKind == FunctionKind::GENERATOR_FUNCTION ||
582                 getKind == FunctionKind::ASYNC_GENERATOR_FUNCTION) {
583                 SetPropertyInlinedProps(glue, func, hclass, funcprotoAccessor,
584                                         Int32(JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX),
585                                         VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
586                 auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
587                                                            ConstantIndex::FUNCTION_NAME_ACCESSOR);
588                 SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
589                                         Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX), VariableType::JS_ANY(),
590                                         MemoryAttribute::NoBarrier());
591                 funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
592                                                       ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
593                 SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
594                                         Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX), VariableType::JS_ANY(),
595                                         MemoryAttribute::NoBarrier());
596                 if (getKind != FunctionKind::BASE_CONSTRUCTOR) {
597                     thisObj = CallRuntime(glue, RTSTUB_ID(InitializeGeneratorFunction), {kind});
598                     SetProtoOrHClassToFunction(glue, func, *thisObj);
599                 }
600             } else if (!JSFunction::IsClassConstructor(getKind)) {
601                 CallRuntime(glue, RTSTUB_ID(FunctionDefineOwnProperty), {func, funcprotoAccessor, kind});
602             }
603             Jump(&exit);
604         } else if (JSFunction::HasAccessor(getKind)) {
605             auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
606                                                        ConstantIndex::FUNCTION_NAME_ACCESSOR);
607             SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX),
608                                     VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
609             funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
610                                                   ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
611             SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX),
612                                     VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
613             Jump(&exit);
614         }
615     } else {
616         SetLexicalEnvToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
617         SetHomeObjectToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
618         SetProtoOrHClassToFunction(glue, func, Hole(), MemoryAttribute::NoBarrier());
619         SetProtoTransRootHClassToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
620         SetWorkNodePointerToFunction(glue, func, NullPtr(), MemoryAttribute::NoBarrier());
621         SetMethodToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
622 
623         BRANCH(HasPrototype(kind), &hasProto, &notProto);
624         Bind(&hasProto);
625         {
626             auto funcprotoAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
627                                                             ConstantIndex::FUNCTION_PROTOTYPE_ACCESSOR);
628             BRANCH(IsBaseKind(kind), &isBase, &notBase);
629             Bind(&isBase);
630             {
631                 SetPropertyInlinedProps(glue, func, hclass, funcprotoAccessor,
632                                         Int32(JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX),
633                                         VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
634                 auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
635                                                            ConstantIndex::FUNCTION_NAME_ACCESSOR);
636                 SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
637                                         Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX), VariableType::JS_ANY(),
638                                         MemoryAttribute::NoBarrier());
639                 funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
640                                                       ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
641                 SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
642                                         Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX), VariableType::JS_ANY(),
643                                         MemoryAttribute::NoBarrier());
644                 BRANCH(IsGeneratorKind(kind), &isGenerator, &exit);
645                 Bind(&isGenerator);
646                 {
647                     thisObj = CallRuntime(glue, RTSTUB_ID(InitializeGeneratorFunction), {kind});
648                     SetProtoOrHClassToFunction(glue, func, *thisObj);
649                     Jump(&exit);
650                 }
651             }
652             Bind(&notBase);
653             {
654                 BRANCH(IsClassConstructorKind(kind), &exit, &notClassConstructor);
655                 Bind(&notClassConstructor);
656                 {
657                     CallRuntime(glue, RTSTUB_ID(FunctionDefineOwnProperty), {func, funcprotoAccessor, kind});
658                     Jump(&exit);
659                 }
660             }
661         }
662         Bind(&notProto);
663         {
664             BRANCH(HasAccessor(kind), &hasAccess, &exit);
665             Bind(&hasAccess);
666             {
667                 auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
668                                                            ConstantIndex::FUNCTION_NAME_ACCESSOR);
669                 SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX),
670                                         VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
671                 funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
672                                                       ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
673                 SetPropertyInlinedProps(glue, func, hclass, funcAccessor,
674                                         Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX),
675                                         VariableType::JS_ANY(), MemoryAttribute::NoBarrier());
676                 Jump(&exit);
677             }
678         }
679     }
680     Bind(&exit);
681     auto emptyProfileTypeInfoCell = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
682                                                            ConstantIndex::EMPTY_PROFILE_TYPE_INFO_CELL_INDEX);
683     SetRawProfileTypeInfoToFunction(glue, func, emptyProfileTypeInfoCell);
684     env->SubCfgExit();
685     return;
686 }
687 
InitializeFunctionWithMethod(GateRef glue,GateRef func,GateRef method,GateRef hclass)688 void BuiltinsFunctionStubBuilder::InitializeFunctionWithMethod(GateRef glue,
689     GateRef func, GateRef method, GateRef hclass)
690 {
691     auto env = GetEnvironment();
692     Label entry(env);
693     env->SubCfgEntry(&entry);
694     Label exit(env);
695 
696     SetCallableToBitfield(glue, hclass, true);
697     SetMethodToFunction(glue, func, method);
698 
699     SetBitFieldToFunction(glue, func, Int32(0));
700     SetMachineCodeToFunction(glue, func, Undefined(), MemoryAttribute::NoBarrier());
701 
702     Label hasCompiledStatus(env);
703     Label tryInitFuncCodeEntry(env);
704     BRANCH(IsAotWithCallField(method), &hasCompiledStatus, &tryInitFuncCodeEntry);
705     Bind(&hasCompiledStatus);
706     {
707         SetCompiledCodeFlagToFunctionFromMethod(glue, func, method);
708         Jump(&tryInitFuncCodeEntry);
709     }
710     // Notice: we set code entries for all function to deal with these situations
711     // 1) AOT compiled method, set AOT compiled code entry
712     // 2) define func with the deopted method, set the AOTToAsmInterpBridge
713     Bind(&tryInitFuncCodeEntry);
714     {
715         SetCodeEntryToFunction(glue, func, method);
716         Jump(&exit);
717     }
718 
719     Bind(&exit);
720     env->SubCfgExit();
721     return;
722 }
723 }  // namespace panda::ecmascript::kungfu
724