Array ReduceRight IR 化

Signed-off-by: liujia178 <liujia178@huawei.com>
This commit is contained in:
liujia178 2024-03-22 18:34:05 +08:00
parent bd96654b3f
commit 69499c2d59
10 changed files with 313 additions and 3 deletions

View File

@ -1826,6 +1826,17 @@ JSTaggedValue BuiltinsArray::ReduceRight(EcmaRuntimeCallInfo *argv)
// e. Decrease k by 1.
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
JSTaggedValue callResult = JSTaggedValue::Undefined();
JSHandle<JSTaggedValue> thisArgHandle = globalConst->GetHandledUndefined();
if (thisObjVal->IsStableJSArray(thread)) {
JSTaggedValue ret = JSStableArray::HandleReduceRightOfStable(thread, thisObjHandle,
callbackFnHandle, accumulator, thisArgHandle, k);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (ret.ToBoolean()) {
return accumulator.GetTaggedValue();
}
}
while (k >= 0) {
key.Update(JSTaggedValue(k));
bool exists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, key));
@ -1833,7 +1844,6 @@ JSTaggedValue BuiltinsArray::ReduceRight(EcmaRuntimeCallInfo *argv)
if (exists) {
JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, key);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> thisArgHandle = globalConst->GetHandledUndefined();
const uint32_t argsLength = 4; // 4: «accumulator, kValue, k, O»
JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
EcmaRuntimeCallInfo *info =

View File

@ -81,7 +81,7 @@
/* Array.prototype.reduce ( callbackfn [ , initialValue ] ) */ \
V("reduce", Reduce, 1, ArrayReduce) \
/* Array.prototype.reduceRight ( callbackfn [ , initialValue ] ) */ \
V("reduceRight", ReduceRight, 1, INVALID) \
V("reduceRight", ReduceRight, 1, ArrayReduceRight) \
/* Array.prototype.reverse ( ) */ \
V("reverse", Reverse, 0, ArrayReverse) \
/* Array.prototype.shift ( ) */ \

View File

@ -2535,6 +2535,211 @@ void BuiltinsArrayStubBuilder::Every(GateRef glue, GateRef thisValue, GateRef nu
}
}
void BuiltinsArrayStubBuilder::ReduceRight(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label thisExists(env);
Label isHeapObject(env);
Label isJsArray(env);
Label defaultConstr(env);
Label isStability(env);
Label notCOWArray(env);
Label equalCls(env);
BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
Bind(&thisExists);
BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
Bind(&isHeapObject);
BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
Bind(&isJsArray);
BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr);
Bind(&defaultConstr);
BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
Bind(&isStability);
BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
Bind(&notCOWArray);
GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
GateRef arrayCls = LoadHClass(thisValue);
BRANCH(Equal(intialHClass, arrayCls), &equalCls, slowPath);
Bind(&equalCls);
DEFVARIABLE(thisLen, VariableType::INT32(), Int32(0));
DEFVARIABLE(accumulator, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(k, VariableType::INT32(), Int32(0));
Label atLeastOneArg(env);
Label callbackFnHandleHeapObject(env);
Label callbackFnHandleCallable(env);
Label noTypeError(env);
Label updateAccumulator(env);
Label thisIsStable(env);
Label thisNotStable(env);
thisLen = GetArrayLength(thisValue);
BRANCH(Int64GreaterThanOrEqual(numArgs, IntPtr(1)), &atLeastOneArg, slowPath);
Bind(&atLeastOneArg);
GateRef callbackFnHandle = GetCallArg0(numArgs);
BRANCH(TaggedIsHeapObject(callbackFnHandle), &callbackFnHandleHeapObject, slowPath);
Bind(&callbackFnHandleHeapObject);
BRANCH(IsCallable(callbackFnHandle), &callbackFnHandleCallable, slowPath);
Bind(&callbackFnHandleCallable);
GateRef thisLenIsZero = Int32Equal(*thisLen, Int32(0));
GateRef numArgsLessThanTwo = Int64LessThan(numArgs, IntPtr(2)); // 2: callbackFn initialValue
BRANCH(BoolAnd(thisLenIsZero, numArgsLessThanTwo), slowPath, &noTypeError);
Bind(&noTypeError);
k = Int32Sub(*thisLen, Int32(1));
BRANCH(Int64Equal(numArgs, IntPtr(2)), &updateAccumulator, slowPath); // 2: callbackFn initialValue
Bind(&updateAccumulator);
accumulator = GetCallArg1(numArgs);
Jump(&thisIsStable);
Bind(&thisIsStable);
{
DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
GateRef argsLength = Int32(4);
NewObjectStubBuilder newBuilder(this);
GateRef argList = newBuilder.NewTaggedArray(glue, argsLength);
Label loopHead(env);
Label next(env);
Label loopEnd(env);
Label loopExit(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
Label nextStep(env);
Label kValueIsHole(env);
Label callDispatch(env);
Label hasProperty(env);
Label hasException0(env);
Label notHasException0(env);
Label hasException1(env);
Label notHasException1(env);
GateRef newLen = GetArrayLength(thisValue);
BRANCH(BoolAnd(IsStableJSArray(glue, thisValue), Int32Equal(*thisLen, newLen)),
&nextStep, &thisNotStable);
Bind(&nextStep);
BRANCH(Int32GreaterThanOrEqual(*k, Int32(0)), &next, &loopExit);
Bind(&next);
kValue = GetTaggedValueWithElementsKind(thisValue, *k);
BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &callDispatch);
Bind(&kValueIsHole);
{
GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*k) });
BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd);
Bind(&hasProperty);
kValue = FastGetPropertyByIndex(glue, thisValue, *k, ProfileOperation());
BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
Bind(&hasException0);
result->WriteVariable(Exception());
Jump(exit);
Bind(&notHasException0);
BRANCH(TaggedIsHole(*kValue), &loopEnd, &callDispatch);
}
Bind(&callDispatch);
{
// callback param 0: accumulator
SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(0), *accumulator);
// callback param 1: currentValue
SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(1), *kValue);
// callback param 2: index
SetValueToTaggedArray(VariableType::INT32(), glue, argList, Int32(2), IntToTaggedInt(*k));
// callback param 3: array
SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(3), thisValue);
GateRef argv = PtrAdd(argList, IntPtr(TaggedArray::DATA_OFFSET));
GateRef callResult = JSCallDispatch(glue, callbackFnHandle, argsLength, 0,
Circuit::NullGate(), JSCallMode::CALL_THIS_ARGV_WITH_RETURN,
{argsLength, argv, Undefined()});
BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
Bind(&hasException1);
{
result->WriteVariable(Exception());
Jump(exit);
}
Bind(&notHasException1);
{
accumulator = callResult;
Jump(&loopEnd);
}
}
}
Bind(&loopEnd);
k = Int32Sub(*k, Int32(1));
LoopEnd(&loopHead);
Bind(&loopExit);
result->WriteVariable(*accumulator);
Jump(exit);
}
Bind(&thisNotStable);
{
DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
GateRef argsLength = Int32(4);
NewObjectStubBuilder newBuilder(this);
GateRef argList = newBuilder.NewTaggedArray(glue, argsLength);
Label loopHead(env);
Label next(env);
Label loopEnd(env);
Label loopExit(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
Label hasProperty(env);
Label hasException0(env);
Label notHasException0(env);
Label callDispatch(env);
Label hasException1(env);
Label notHasException1(env);
BRANCH(Int32GreaterThanOrEqual(*k, Int32(0)), &next, &loopExit);
Bind(&next);
GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*k) });
BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd);
Bind(&hasProperty);
kValue = FastGetPropertyByIndex(glue, thisValue, *k, ProfileOperation());
BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
Bind(&hasException0);
result->WriteVariable(Exception());
Jump(exit);
Bind(&notHasException0);
BRANCH(TaggedIsHole(*kValue), &loopEnd, &callDispatch);
Bind(&callDispatch);
{
// callback param 0: accumulator
SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(0), *accumulator);
// callback param 1: currentValue
SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(1), *kValue);
// callback param 2: index
SetValueToTaggedArray(VariableType::INT32(), glue, argList, Int32(2), IntToTaggedInt(*k));
// callback param 3: array
SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(3), thisValue);
GateRef argv = PtrAdd(argList, IntPtr(TaggedArray::DATA_OFFSET));
GateRef callResult = JSCallDispatch(glue, callbackFnHandle, argsLength, 0,
Circuit::NullGate(), JSCallMode::CALL_THIS_ARGV_WITH_RETURN,
{argsLength, argv, Undefined()});
BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
Bind(&hasException1);
{
result->WriteVariable(Exception());
Jump(exit);
}
Bind(&notHasException1);
{
accumulator = callResult;
Jump(&loopEnd);
}
}
}
Bind(&loopEnd);
k = Int32Sub(*k, Int32(1));
LoopEnd(&loopHead);
Bind(&loopExit);
result->WriteVariable(*accumulator);
Jump(exit);
}
}
void BuiltinsArrayStubBuilder::FindLastIndex(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable *result, Label *exit, Label *slowPath)
{

View File

@ -83,6 +83,8 @@ public:
void Every(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable *result, Label *exit, Label *slowPath);
void ReduceRight(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath);
void Map(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath);
void FindLastIndex(GateRef glue, GateRef thisValue, GateRef numArgs,

View File

@ -84,6 +84,7 @@ namespace panda::ecmascript::kungfu {
V(ArrayIncludes) \
V(ArrayFrom) \
V(ArraySplice) \
V(ArrayReduceRight) \
V(ArrayCopyWithin) \
V(ArrayEvery) \
V(ArrayFindLastIndex) \

View File

@ -343,6 +343,7 @@ DECLARE_BUILTINS(Array##Method)
V(Every, JS_ANY) \
V(FindLastIndex, JS_ANY) \
V(FindLast, JS_ANY) \
V(ReduceRight, JS_ANY) \
V(Map, JS_ANY)
DECLARE_BUILTINS(SORT)

View File

@ -1226,4 +1226,54 @@ JSTaggedValue JSStableArray::HandleFindLastOfStable(JSThread *thread, JSHandle<J
}
return callResult;
}
JSTaggedValue JSStableArray::HandleReduceRightOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle,
JSHandle<JSTaggedValue> callbackFnHandle,
JSMutableHandle<JSTaggedValue> &accumulator,
JSHandle<JSTaggedValue> thisArgHandle, int64_t &k)
{
JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Hole());
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
JSTaggedValue callResult = JSTaggedValue::Undefined();
JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
const int32_t argsLength = 4; // 4: «accumulator, kValue, k, O»
int64_t len = static_cast<int64_t>(base::ArrayHelper::GetArrayLength(thread, thisObjVal));
while (k >= 0) {
key.Update(JSTaggedValue(k));
kValue.Update(ElementAccessor::Get(thisObjHandle, k));
if (!kValue.GetTaggedValue().IsHole()) {
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
info->SetCallArg(accumulator.GetTaggedValue(), kValue.GetTaggedValue(),
key.GetTaggedValue(), thisObjVal.GetTaggedValue());
callResult = JSFunction::Call(info);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
accumulator.Update(callResult);
} else {
bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, key);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (exists) {
auto res = JSArray::FastGetPropertyByValue(thread, thisObjVal, key).GetTaggedValue();
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
kValue.Update(res);
EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle,
thisArgHandle, undefined, argsLength);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
info->SetCallArg(accumulator.GetTaggedValue(), kValue.GetTaggedValue(),
key.GetTaggedValue(), thisObjVal.GetTaggedValue());
callResult = JSFunction::Call(info);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
accumulator.Update(callResult);
}
}
k--;
int64_t newLen = static_cast<int64_t>(base::ArrayHelper::GetArrayLength(thread, thisObjVal));
if (!thisObjVal->IsStableJSArray(thread) || newLen != len) {
return base::BuiltinsBase::GetTaggedBoolean(false);
}
}
return base::BuiltinsBase::GetTaggedBoolean(true);
}
} // namespace panda::ecmascript

View File

@ -79,6 +79,10 @@ public:
JSHandle<JSTaggedValue> callbackFnHandle,
JSHandle<JSTaggedValue> thisArgHandle,
JSMutableHandle<JSTaggedValue> &kValue, int64_t &k);
static JSTaggedValue HandleReduceRightOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle,
JSHandle<JSTaggedValue> callbackFnHandle,
JSMutableHandle<JSTaggedValue> &accumulator,
JSHandle<JSTaggedValue> thisArgHandle, int64_t &k);
private:
static void SetSepValue(JSHandle<EcmaString> sepStringHandle, int &sep, uint32_t &sepLength);

View File

@ -530,4 +530,37 @@ print(result_every2);
var result_every3 = arr_every3.every(testEvery);
print(result_every3);
var result_every4 = arr_every4.every(testEvery4);
print(result_every4);
print(result_every4);
// Test case for reduceRight()
var arr_reduceRight1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var arr_reduceRight2 = new Array();
function testReduceRight(accumulator, element, index, array) {
if (index == 0) {
array.length = 6;
}
return accumulator + element;
}
function testReduceRight4(accumulator, element, index, array) {
array.pop();
array.pop();
return accumulator + element;
}
for (let i = 0; i < 10; i++) arr_reduceRight2[i] = i;
var arr_reduceRight3 = new Array();
for (let i = 0; i < 10; i++) {
if (i < 9) {
continue;
}
arr_reduceRight3[i] = i;
}
var arr_reduceRight4 = new Array();
for (let i = 0; i < 10; i++) arr_reduceRight4[i] = i;
var result_reduceRight1 = arr_reduceRight1.reduceRight(testReduceRight, 100);
print(result_reduceRight1);
var result_reduceRight2 = arr_reduceRight2.reduceRight(testReduceRight, 100);
print(result_reduceRight2);
var result_reduceRight3 = arr_reduceRight3.reduceRight(testReduceRight, 100);
print(result_reduceRight3);
var result_reduceRight4 = arr_reduceRight4.reduceRight(testReduceRight4, 100);
print(result_reduceRight4);

View File

@ -155,3 +155,7 @@ true
true
true
true
145
145
109
125