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, ¬Proto);
624 Bind(&hasProto);
625 {
626 auto funcprotoAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
627 ConstantIndex::FUNCTION_PROTOTYPE_ACCESSOR);
628 BRANCH(IsBaseKind(kind), &isBase, ¬Base);
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(¬Base);
653 {
654 BRANCH(IsClassConstructorKind(kind), &exit, ¬ClassConstructor);
655 Bind(¬ClassConstructor);
656 {
657 CallRuntime(glue, RTSTUB_ID(FunctionDefineOwnProperty), {func, funcprotoAccessor, kind});
658 Jump(&exit);
659 }
660 }
661 }
662 Bind(¬Proto);
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