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, ¬Proto);
631 Bind(&hasProto);
632 {
633 auto funcprotoAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
634 ConstantIndex::FUNCTION_PROTOTYPE_ACCESSOR);
635 BRANCH(IsBaseKind(kind), &isBase, ¬Base);
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(¬Base);
660 {
661 BRANCH(IsClassConstructorKind(kind), &exit, ¬ClassConstructor);
662 Bind(¬ClassConstructor);
663 {
664 CallRuntime(glue, RTSTUB_ID(FunctionDefineOwnProperty), {func, funcprotoAccessor, kind});
665 Jump(&exit);
666 }
667 }
668 }
669 Bind(¬Proto);
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