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