/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/compiler/builtins/containers_stub_builder.h" #include "ecmascript/compiler/builtins/containers_vector_stub_builder.h" namespace panda::ecmascript::kungfu { // common IR for containers apis that use function call void ContainersStubBuilder::ContainersCommonFuncCall(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type) { auto env = GetEnvironment(); DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue); DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(key, VariableType::INT64(), Int64(0)); DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(length, VariableType::INT32(), Int32(0)); DEFVARIABLE(k, VariableType::INT32(), Int32(0)); Label valueIsJSAPIVector(env); Label valueNotJSAPIVector(env); Label objIsJSProxy(env); Label objNotJSProxy(env); Label objIsJSAPIVector(env); Label thisArgUndefined(env); Label thisArgNotUndefined(env); Label callbackUndefined(env); Label callbackNotUndefined(env); Label nextCount(env); Label loopHead(env); Label loopEnd(env); Label next(env); Label afterLoop(env); GateRef callbackFnHandle; Branch(IsContainer(*thisObj, type), &valueIsJSAPIVector, &valueNotJSAPIVector); Bind(&valueNotJSAPIVector); { Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy); Bind(&objIsJSProxy); { GateRef tempObj = GetTarget(*thisObj); Branch(IsContainer(tempObj, type), &objIsJSAPIVector, slowPath); Bind(&objIsJSAPIVector); { thisObj = tempObj; Jump(&valueIsJSAPIVector); } } Bind(&objNotJSProxy); Jump(slowPath); } Bind(&valueIsJSAPIVector); { Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined); Bind(&callbackUndefined); Jump(slowPath); Bind(&callbackNotUndefined); { Label isCall(env); Label notCall(env); Label isHeapObj(env); callbackFnHandle = GetCallArg0(numArgs); Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath); Bind(&isHeapObj); Branch(IsCallable(callbackFnHandle), &isCall, ¬Call); Bind(¬Call); Jump(slowPath); Bind(&isCall); { Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined); Bind(&thisArgUndefined); Jump(&nextCount); Bind(&thisArgNotUndefined); thisArg = GetCallArg1(numArgs); Jump(&nextCount); } } } Bind(&nextCount); { length = ContainerGetSize(*thisObj, type); Jump(&loopHead); LoopBegin(&loopHead); { Label lenChange(env); Label hasException(env); Label notHasException(env); Label setValue(env); Branch(Int32LessThan(*k, *length), &next, &afterLoop); Bind(&next); { kValue = ContainerGetValue(*thisObj, *k, type); if (IsPlainArray(type)) { key = PlainArrayGetKey(*thisObj, *k); } else { key = IntToTaggedInt(*k); } GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *kValue, *key, *thisObj }); Branch(HasPendingException(glue), &hasException, ¬HasException); Bind(&hasException); { result->WriteVariable(retValue); Jump(exit); } Bind(¬HasException); GateRef tempLen = ContainerGetSize(*thisObj, type); Branch(Int32NotEqual(tempLen, *length), &lenChange, &setValue); Bind(&lenChange); length = tempLen; Branch(Int32GreaterThanOrEqual(*k, *length), &afterLoop, &setValue); Bind(&setValue); if (IsReplaceAllElements(type)) { ContainerSet(glue, *thisObj, *k, retValue, type); } Jump(&loopEnd); } } Bind(&loopEnd); k = Int32Add(*k, Int32(1)); LoopEnd(&loopHead); } Bind(&afterLoop); Jump(exit); } void ContainersStubBuilder::QueueCommonFuncCall(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type) { auto env = GetEnvironment(); DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue); DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(key, VariableType::INT64(), Int64(0)); DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(length, VariableType::INT32(), Int32(0)); DEFVARIABLE(k, VariableType::INT32(), Int32(0)); DEFVARIABLE(index, VariableType::INT32(), Int32(0)); Label valueIsJSAPIVector(env); Label valueNotJSAPIVector(env); Label objIsJSProxy(env); Label objNotJSProxy(env); Label objIsJSAPIVector(env); Label thisArgUndefined(env); Label thisArgNotUndefined(env); Label callbackUndefined(env); Label callbackNotUndefined(env); Label nextCount(env); Label loopHead(env); Label loopEnd(env); Label next(env); Label afterLoop(env); GateRef callbackFnHandle; Branch(IsContainer(*thisObj, type), &valueIsJSAPIVector, &valueNotJSAPIVector); Bind(&valueNotJSAPIVector); { Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy); Bind(&objIsJSProxy); { GateRef tempObj = GetTarget(*thisObj); Branch(IsContainer(tempObj, type), &objIsJSAPIVector, slowPath); Bind(&objIsJSAPIVector); { thisObj = tempObj; Jump(&valueIsJSAPIVector); } } Bind(&objNotJSProxy); Jump(slowPath); } Bind(&valueIsJSAPIVector); { Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined); Bind(&callbackUndefined); Jump(slowPath); Bind(&callbackNotUndefined); { Label isCall(env); Label notCall(env); Label isHeapObj(env); callbackFnHandle = GetCallArg0(numArgs); Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath); Bind(&isHeapObj); Branch(IsCallable(callbackFnHandle), &isCall, ¬Call); Bind(¬Call); Jump(slowPath); Bind(&isCall); { Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined); Bind(&thisArgUndefined); Jump(&nextCount); Bind(&thisArgNotUndefined); thisArg = GetCallArg1(numArgs); Jump(&nextCount); } } } Bind(&nextCount); { length = ContainerGetSize(*thisObj, type); Jump(&loopHead); LoopBegin(&loopHead); { Label lenChange(env); Label hasException(env); Label notHasException(env); Label setValue(env); Branch(Int32LessThan(*k, *length), &next, &afterLoop); Bind(&next); { kValue = ContainerGetValue(*thisObj, *index, type); index = QueueGetNextPosition(*thisObj, *index); key = IntToTaggedInt(*k); GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *kValue, *key, *thisObj }); Branch(HasPendingException(glue), &hasException, ¬HasException); Bind(&hasException); { result->WriteVariable(retValue); Jump(exit); } Bind(¬HasException); Jump(&loopEnd); } } Bind(&loopEnd); k = Int32Add(*k, Int32(1)); LoopEnd(&loopHead); } Bind(&afterLoop); Jump(exit); } void ContainersStubBuilder::DequeCommonFuncCall(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type) { auto env = GetEnvironment(); DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue); DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(key, VariableType::INT64(), Int64(0)); DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(length, VariableType::INT32(), Int32(0)); DEFVARIABLE(first, VariableType::INT32(), Int32(0)); DEFVARIABLE(index, VariableType::INT32(), Int32(0)); Label valueIsJSAPIVector(env); Label valueNotJSAPIVector(env); Label objIsJSProxy(env); Label objNotJSProxy(env); Label objIsJSAPIVector(env); Label thisArgUndefined(env); Label thisArgNotUndefined(env); Label callbackUndefined(env); Label callbackNotUndefined(env); Label nextCount(env); Label loopHead(env); Label loopEnd(env); Label next(env); Label afterLoop(env); GateRef callbackFnHandle; Branch(IsContainer(*thisObj, type), &valueIsJSAPIVector, &valueNotJSAPIVector); Bind(&valueNotJSAPIVector); { Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy); Bind(&objIsJSProxy); { GateRef tempObj = GetTarget(*thisObj); Branch(IsContainer(tempObj, type), &objIsJSAPIVector, slowPath); Bind(&objIsJSAPIVector); { thisObj = tempObj; Jump(&valueIsJSAPIVector); } } Bind(&objNotJSProxy); Jump(slowPath); } Bind(&valueIsJSAPIVector); { Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined); Bind(&callbackUndefined); Jump(slowPath); Bind(&callbackNotUndefined); { Label isCall(env); Label notCall(env); Label isHeapObj(env); callbackFnHandle = GetCallArg0(numArgs); Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath); Bind(&isHeapObj); Branch(IsCallable(callbackFnHandle), &isCall, ¬Call); Bind(¬Call); Jump(slowPath); Bind(&isCall); { Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined); Bind(&thisArgUndefined); Jump(&nextCount); Bind(&thisArgNotUndefined); thisArg = GetCallArg1(numArgs); Jump(&nextCount); } } } Bind(&nextCount); { ContainersDequeStubBuilder dequeBuilder(this); first = dequeBuilder.GetFirst(*thisObj); GateRef last = dequeBuilder.GetLast(*thisObj); GateRef capacity = dequeBuilder.GetElementsLength(*thisObj); Jump(&loopHead); LoopBegin(&loopHead); { Label lenChange(env); Label hasException(env); Label notHasException(env); Label setValue(env); Branch(Int32NotEqual(*first, last), &next, &afterLoop); Bind(&next); { kValue = ContainerGetValue(*thisObj, *index, type); key = IntToTaggedInt(*index); GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *kValue, *key, *thisObj }); Branch(HasPendingException(glue), &hasException, ¬HasException); Bind(&hasException); { result->WriteVariable(retValue); Jump(exit); } Bind(¬HasException); Jump(&loopEnd); } } Bind(&loopEnd); first = Int32Mod(Int32Add(*first, Int32(1)), capacity); index = Int32Add(*index, Int32(1)); LoopEnd(&loopHead); } Bind(&afterLoop); Jump(exit); } void ContainersStubBuilder::ContainersLightWeightCall(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type) { auto env = GetEnvironment(); DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue); DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(key, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(value, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(length, VariableType::INT32(), Int32(0)); DEFVARIABLE(index, VariableType::INT32(), Int32(0)); Label valueIsJSAPILightWeight(env); Label valueNotJSAPILightWeight(env); Label objIsJSProxy(env); Label objNotJSProxy(env); Label objIsJSAPILightWeight(env); Label thisArgUndefined(env); Label thisArgNotUndefined(env); Label callbackUndefined(env); Label callbackNotUndefined(env); Label nextCount(env); Label loopHead(env); Label loopEnd(env); Label next(env); Label afterLoop(env); GateRef callbackFnHandle; Branch(IsContainer(*thisObj, type), &valueIsJSAPILightWeight, &valueNotJSAPILightWeight); Bind(&valueNotJSAPILightWeight); { Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy); Bind(&objIsJSProxy); { GateRef tempObj = GetTarget(*thisObj); Branch(IsContainer(tempObj, type), &objIsJSAPILightWeight, slowPath); Bind(&objIsJSAPILightWeight); { thisObj = tempObj; Jump(&valueIsJSAPILightWeight); } } Bind(&objNotJSProxy); Jump(slowPath); } Bind(&valueIsJSAPILightWeight); { Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined); Bind(&callbackUndefined); Jump(slowPath); Bind(&callbackNotUndefined); { Label isCall(env); Label notCall(env); Label isHeapObj(env); callbackFnHandle = GetCallArg0(numArgs); Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath); Bind(&isHeapObj); Branch(IsCallable(callbackFnHandle), &isCall, ¬Call); Bind(¬Call); Jump(slowPath); Bind(&isCall); { Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined); Bind(&thisArgUndefined); Jump(&nextCount); Bind(&thisArgNotUndefined); thisArg = GetCallArg1(numArgs); Jump(&nextCount); } } } Bind(&nextCount); { length = ContainerGetSize(*thisObj, type); Jump(&loopHead); LoopBegin(&loopHead); { Label lenChange(env); Label hasException(env); Label notHasException(env); Branch(Int32LessThan(*index, *length), &next, &afterLoop); Bind(&next); { value = ContainerGetValue(*thisObj, *index, type); key = ContainerGetKey(*thisObj, *index, type); GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *value, *key, *thisObj }); Branch(HasPendingException(glue), &hasException, ¬HasException); Bind(&hasException); { result->WriteVariable(retValue); Jump(exit); } Bind(¬HasException); GateRef currentLen = ContainerGetSize(*thisObj, type); Branch(Int32NotEqual(currentLen, *length), &lenChange, &loopEnd); Bind(&lenChange); length = currentLen; Jump(&loopEnd); } } Bind(&loopEnd); index = Int32Add(*index, Int32(1)); LoopEnd(&loopHead); } Bind(&afterLoop); Jump(exit); } void ContainersStubBuilder::ContainersHashCall(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type) { auto env = GetEnvironment(); DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue); DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(node, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(key, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(value, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(length, VariableType::INT32(), Int32(0)); DEFVARIABLE(index, VariableType::INT32(), Int32(0)); Label valueIsJSAPIHash(env); Label valueNotJSAPIHash(env); Label objIsJSProxy(env); Label objNotJSProxy(env); Label objIsJSAPIHash(env); Label thisArgUndefined(env); Label thisArgNotUndefined(env); Label callbackUndefined(env); Label callbackNotUndefined(env); Label nextCount(env); Label nodeNotHole(env); Label nodeIsLinked(env); Label nodeIsRBTree(env); Label loopLinked(env); Label loopHead(env); Label loopEnd(env); Label next(env); Label afterLoop(env); GateRef callbackFnHandle; Branch(IsContainer(*thisObj, type), &valueIsJSAPIHash, &valueNotJSAPIHash); Bind(&valueNotJSAPIHash); { Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy); Bind(&objIsJSProxy); { GateRef tempObj = GetTarget(*thisObj); Branch(IsContainer(tempObj, type), &objIsJSAPIHash, slowPath); Bind(&objIsJSAPIHash); { thisObj = tempObj; Jump(&valueIsJSAPIHash); } } Bind(&objNotJSProxy); Jump(slowPath); } Bind(&valueIsJSAPIHash); { Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined); Bind(&callbackUndefined); Jump(slowPath); Bind(&callbackNotUndefined); { Label isCall(env); Label notCall(env); Label isHeapObj(env); callbackFnHandle = GetCallArg0(numArgs); Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, ¬Call); Bind(&isHeapObj); Branch(IsCallable(callbackFnHandle), &isCall, ¬Call); Bind(¬Call); Jump(slowPath); Bind(&isCall); { Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined); Bind(&thisArgUndefined); Jump(&nextCount); Bind(&thisArgNotUndefined); thisArg = GetCallArg1(numArgs); Jump(&nextCount); } } } Bind(&nextCount); { length = ContainerGetSize(*thisObj, type); Jump(&loopHead); LoopBegin(&loopHead); { Label hasExceptionLinked(env); Label notHasExceptionLinked(env); Label hasExceptionRBTree(env); Label notHasExceptionRBTree(env); Branch(Int32LessThan(*index, *length), &next, &afterLoop); Bind(&next); { node = ContainerGetNode(*thisObj, *index, type); Branch(TaggedIsHole(*node), &loopEnd, &nodeNotHole); Bind(&nodeNotHole); Branch(IsLinkedNode(*node), &nodeIsLinked, &nodeIsRBTree); LoopBegin(&nodeIsLinked); { value = Load(VariableType::JS_POINTER(), *node, IntPtr( type == ContainersType::HASHSET_FOREACH ? LinkedNode::KEY_OFFSET : LinkedNode::VALUE_OFFSET)); key = Load(VariableType::JS_POINTER(), *node, IntPtr(LinkedNode::KEY_OFFSET)); GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *value, *key, *thisObj }); Branch(HasPendingException(glue), &hasExceptionLinked, ¬HasExceptionLinked); Bind(&hasExceptionLinked); { result->WriteVariable(retValue); Jump(exit); } Bind(¬HasExceptionLinked); node = Load(VariableType::JS_POINTER(), *node, IntPtr(LinkedNode::NEXT_OFFSET)); Branch(TaggedIsHole(*node), &loopEnd, &loopLinked); } Bind(&loopLinked); LoopEnd(&nodeIsLinked); Bind(&nodeIsRBTree); { GateRef retValue = CallRuntime(glue, RTSTUB_ID(ContainerRBTreeForEach), { *node, callbackFnHandle, *thisArg, *thisObj, IntToTaggedInt(Int32(static_cast<int32_t>(type))) }); Branch(HasPendingException(glue), &hasExceptionRBTree, ¬HasExceptionRBTree); Bind(&hasExceptionRBTree); { result->WriteVariable(retValue); Jump(exit); } Bind(¬HasExceptionRBTree); Jump(&loopEnd); } } } Bind(&loopEnd); index = Int32Add(*index, Int32(1)); LoopEnd(&loopHead); } Bind(&afterLoop); Jump(exit); } void ContainersStubBuilder::ContainersLinkedListCall(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type) { auto env = GetEnvironment(); DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue); DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(valueNode, VariableType::INT32(), Int32(0)); DEFVARIABLE(key, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(value, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(length, VariableType::INT32(), Int32(0)); DEFVARIABLE(index, VariableType::INT32(), Int32(0)); Label valueIsJSAPILinkedList(env); Label valueNotJSAPILinkedList(env); Label objIsJSProxy(env); Label objNotJSProxy(env); Label objIsJSAPILinkedList(env); Label thisArgUndefined(env); Label thisArgNotUndefined(env); Label callbackUndefined(env); Label callbackNotUndefined(env); Label nextCount(env); Label valueNotHole(env); Label loopHead(env); Label loopEnd(env); Label next(env); Label afterLoop(env); GateRef callbackFnHandle; Branch(IsContainer(*thisObj, type), &valueIsJSAPILinkedList, &valueNotJSAPILinkedList); Bind(&valueNotJSAPILinkedList); { Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy); Bind(&objIsJSProxy); { GateRef tempObj = GetTarget(*thisObj); Branch(IsContainer(tempObj, type), &objIsJSAPILinkedList, slowPath); Bind(&objIsJSAPILinkedList); { thisObj = tempObj; Jump(&valueIsJSAPILinkedList); } } Bind(&objNotJSProxy); Jump(slowPath); } Bind(&valueIsJSAPILinkedList); { Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined); Bind(&callbackUndefined); Jump(slowPath); Bind(&callbackNotUndefined); { Label isCall(env); Label notCall(env); Label isHeapObj(env); callbackFnHandle = GetCallArg0(numArgs); Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, ¬Call); Bind(&isHeapObj); Branch(IsCallable(callbackFnHandle), &isCall, ¬Call); Bind(¬Call); Jump(slowPath); Bind(&isCall); { Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined); Bind(&thisArgUndefined); Jump(&nextCount); Bind(&thisArgNotUndefined); thisArg = GetCallArg1(numArgs); Jump(&nextCount); } } } Bind(&nextCount); { length = ContainerGetSize(*thisObj, type); valueNode = Int32(TaggedList<TaggedArray>::ELEMENTS_START_INDEX); Jump(&loopHead); LoopBegin(&loopHead); { Label hasException(env); Label notHasException(env); Branch(Int32LessThan(*index, *length), &next, &afterLoop); Bind(&next); { valueNode = TaggedGetInt(ContainerGetNode(*thisObj, Int32Add(*valueNode, Int32(TaggedList<TaggedArray>::NEXT_PTR_OFFSET)), type)); value = ContainerGetNode(*thisObj, *valueNode, type); Branch(TaggedIsHole(*value), &loopEnd, &valueNotHole); Bind(&valueNotHole); key = IntToTaggedInt(*index); GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *value, *key, *thisObj }); Branch(HasPendingException(glue), &hasException, ¬HasException); Bind(&hasException); { result->WriteVariable(retValue); Jump(exit); } Bind(¬HasException); Jump(&loopEnd); } } Bind(&loopEnd); index = Int32Add(*index, Int32(1)); LoopEnd(&loopHead); } Bind(&afterLoop); Jump(exit); } } // namespace panda::ecmascript::kungfu