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