diff --git a/ecmascript/builtins/builtins_array.cpp b/ecmascript/builtins/builtins_array.cpp index 6c5679a7ee1d13dc0aef0d735a583fef52d5c5f7..4992971f66e3d1dff3dea8d682f70840d278a52d 100644 --- a/ecmascript/builtins/builtins_array.cpp +++ b/ecmascript/builtins/builtins_array.cpp @@ -1675,7 +1675,7 @@ JSTaggedValue BuiltinsArray::Reduce(EcmaRuntimeCallInfo *argv) JSHandle thisObjVal(thisObjHandle); // 3. Let len be ToLength(Get(O, "length")). - int64_t len = ArrayHelper::GetLength(thread, thisObjVal); + int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); // 4. ReturnIfAbrupt(len). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -1750,7 +1750,7 @@ JSTaggedValue BuiltinsArray::ReduceRight(EcmaRuntimeCallInfo *argv) JSHandle thisObjVal(thisObjHandle); // 3. Let len be ToLength(Get(O, "length")). - int64_t len = ArrayHelper::GetLength(thread, thisObjVal); + int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); // 4. ReturnIfAbrupt(len). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); diff --git a/ecmascript/builtins/builtins_typedarray.cpp b/ecmascript/builtins/builtins_typedarray.cpp index 5e7a6bc5d1d0583511edec7e64c380a3165303d8..9956d8c57a40d40221b1efd06dfe23216a89856e 100644 --- a/ecmascript/builtins/builtins_typedarray.cpp +++ b/ecmascript/builtins/builtins_typedarray.cpp @@ -982,10 +982,80 @@ JSTaggedValue BuiltinsTypedArray::Reduce(EcmaRuntimeCallInfo *argv) { ASSERT(argv); BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Reduce); - if (!GetThis(argv)->IsTypedArray()) { - THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + uint32_t argc = argv->GetArgsNumber(); + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "This is not a TypedArray.", JSTaggedValue::Exception()); + } + // 1. Let O be ToObject(this value). + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + int64_t len = JSHandle::Cast(thisObjHandle)->GetArrayLength(); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + JSTaggedValue buffer = JSHandle::Cast(thisHandle)->GetViewedArrayBufferOrByteArray(); + if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) { + THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.", + JSTaggedValue::Exception()); } - return BuiltinsArray::Reduce(argv); + + // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); + } + + // 6. If len is 0 and initialValue is not present, throw a TypeError exception. + if (len == 0 && argc < 2) { // 2:2 means the number of parameters + THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); + } + + // 7. Let k be 0. + // 8. If initialValue is present, then + // a. Set accumulator to initialValue. + // 9. Else initialValue is not present, + // a. Let kPresent be false. + // b. Repeat, while kPresent is false and k < len + // i. Let Pk be ToString(k). + // ii. Let kPresent be HasProperty(O, Pk). + // iii. ReturnIfAbrupt(kPresent). + // iv. If kPresent is true, then + // 1. Let accumulator be Get(O, Pk). + // 2. ReturnIfAbrupt(accumulator). + // v. Increase k by 1. + // c. If kPresent is false, throw a TypeError exception. + int64_t k = 0; + JSMutableHandle accumulator(thread, JSTaggedValue::Undefined()); + if (argc == 2) { // 2:2 means the number of parameters + accumulator.Update(GetCallArg(argv, 1).GetTaggedValue()); + } else { + bool kPresent = false; + while (!kPresent && k < len) { + kPresent = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, k)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (kPresent) { + accumulator.Update(JSArray::FastGetPropertyByValue(thread, thisObjVal, k).GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + k++; + } + if (!kPresent) { + THROW_TYPE_ERROR_AND_RETURN(thread, "accumulator can't be initialized.", JSTaggedValue::Exception()); + } + } + + if (thisObjVal->IsStableJSArray(thread)) { + JSStableArray::Reduce(thread, thisObjHandle, callbackFnHandle, accumulator, k, len); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + return BuiltinsArray::ReduceUnStableJSArray(thread, thisHandle, thisObjVal, k, len, accumulator, callbackFnHandle); } // 22.2.3.20 @@ -993,10 +1063,113 @@ JSTaggedValue BuiltinsTypedArray::ReduceRight(EcmaRuntimeCallInfo *argv) { ASSERT(argv); BUILTINS_API_TRACE(argv->GetThread(), TypedArray, ReduceRight); - if (!GetThis(argv)->IsTypedArray()) { - THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + + uint32_t argc = argv->GetArgsNumber(); + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "This is not a TypedArray.", JSTaggedValue::Exception()); + } + // 1. Let O be ToObject(this value). + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + int64_t len =JSHandle::Cast(thisObjVal)->GetArrayLength(); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + JSTaggedValue buffer = JSHandle::Cast(thisHandle)->GetViewedArrayBufferOrByteArray(); + if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) { + THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.", + JSTaggedValue::Exception()); + } + + // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); + } + + // 6. If len is 0 and initialValue is not present, throw a TypeError exception. + if (len == 0 && argc < 2) { // 2:2 means the number of parameters + THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); + } + + // 7. Let k be len-1. + int64_t k = len - 1; + // 8. If initialValue is present, then + // a. Set accumulator to initialValue. + // 9. Else initialValue is not present, + // a. Let kPresent be false. + // b. Repeat, while kPresent is false and k ≥ 0 + // i. Let Pk be ToString(k). + // ii. Let kPresent be HasProperty(O, Pk). + // iii. ReturnIfAbrupt(kPresent). + // iv. If kPresent is true, then + // 1. Let accumulator be Get(O, Pk). + // 2. ReturnIfAbrupt(accumulator). + // v. Decrease k by 1. + // c. If kPresent is false, throw a TypeError exception. + JSMutableHandle accumulator(thread, JSTaggedValue::Undefined()); + if (argc == 2) { // 2:2 means the number of parameters + accumulator.Update(GetCallArg(argv, 1).GetTaggedValue()); + } else { + bool kPresent = false; + while (!kPresent && k >= 0) { + kPresent = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, k)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (kPresent) { + accumulator.Update(JSArray::FastGetPropertyByValue(thread, thisObjVal, k).GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + k--; + } + if (!kPresent) { + THROW_TYPE_ERROR_AND_RETURN(thread, "accumulator can't be initialized.", JSTaggedValue::Exception()); + } } - return BuiltinsArray::ReduceRight(argv); + + // 10. Repeat, while k ≥ 0 + // a. Let Pk be ToString(k). + // b. Let kPresent be HasProperty(O, Pk). + // c. ReturnIfAbrupt(kPresent). + // d. If kPresent is true, then + // i. Let kValue be Get(O, Pk). + // ii. ReturnIfAbrupt(kValue). + // iii. Let accumulator be Call(callbackfn, undefined, «accumulator, kValue, k, O»). + // iv. ReturnIfAbrupt(accumulator). + // e. Decrease k by 1. + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSTaggedValue callResult = JSTaggedValue::Undefined(); + while (k >= 0) { + key.Update(JSTaggedValue(k)); + bool exists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, key)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (exists) { + JSHandle kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, key); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisArgHandle = globalConst->GetHandledUndefined(); + const uint32_t argsLength = 4; // 4: «accumulator, kValue, k, O» + JSHandle undefined = globalConst->GetHandledUndefined(); + 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--; + } + + // 11. Return accumulator. + return accumulator.GetTaggedValue(); } // 22.2.3.21