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