From de9b016e65665d913a746fb832e1cb61e81f9f1a Mon Sep 17 00:00:00 2001 From: xwcai98 Date: Tue, 22 Jul 2025 21:17:56 +0800 Subject: [PATCH] Fix typedarray constructor Issue: Signed-off-by: xwcai98 Change-Id: Ic1d84dc1d94a8b3f53b128324c3f6fee1e3f099b --- ecmascript/base/typed_array_helper.cpp | 12 +-- ecmascript/base/typed_array_helper.h | 2 +- .../builtins_typedarray_stub_builder.cpp | 10 ++- .../builtins_typedarray_stub_builder.h | 2 +- ecmascript/js_stable_array.cpp | 78 +++++++++++++++++++ ecmascript/js_stable_array.h | 4 + ecmascript/stubs/runtime_stub_list.h | 2 +- ecmascript/stubs/runtime_stubs.cpp | 6 +- test/moduletest/typearray/typearray.js | 16 ++++ 9 files changed, 116 insertions(+), 16 deletions(-) diff --git a/ecmascript/base/typed_array_helper.cpp b/ecmascript/base/typed_array_helper.cpp index bfb47aa435..bb24b0d6b2 100644 --- a/ecmascript/base/typed_array_helper.cpp +++ b/ecmascript/base/typed_array_helper.cpp @@ -69,7 +69,7 @@ JSTaggedValue TypedArrayHelper::TypedArrayConstructor(EcmaRuntimeCallInfo *argv, return TypedArrayHelper::CreateFromArrayBuffer(argv, obj, arrayType); } if (firstArg->IsStableJSArray(thread)) { - return TypedArrayHelper::FastCopyElementFromArray(argv, obj, arrayType); + return TypedArrayHelper::FastCopyElementFromArrayForCtor(argv, obj, arrayType); } if (firstArg->IsSendableArrayBuffer()) { auto error = ContainerError::BusinessError(thread, containers::ErrorFlag::TYPE_ERROR, @@ -127,7 +127,7 @@ JSTaggedValue TypedArrayHelper::SharedTypedArrayConstructor(EcmaRuntimeCallInfo THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } if (firstArg->IsStableJSArray(thread)) { - return TypedArrayHelper::FastCopyElementFromArray(argv, obj, arrayType); + return TypedArrayHelper::FastCopyElementFromArrayForCtor(argv, obj, arrayType); } return TypedArrayHelper::CreateFromOrdinaryObject(argv, obj, arrayType); } @@ -295,13 +295,13 @@ JSHandle TypedArrayHelper::AllocateTypedArrayBuffer( +template JSTaggedValue TypedArrayHelper::FastCopyElementFromArrayForCtor( EcmaRuntimeCallInfo *argv, const JSHandle &obj, const DataViewType arrayType); -template JSTaggedValue TypedArrayHelper::FastCopyElementFromArray( +template JSTaggedValue TypedArrayHelper::FastCopyElementFromArrayForCtor( EcmaRuntimeCallInfo *argv, const JSHandle &obj, const DataViewType arrayType); template -JSTaggedValue TypedArrayHelper::FastCopyElementFromArray( +JSTaggedValue TypedArrayHelper::FastCopyElementFromArrayForCtor( EcmaRuntimeCallInfo *argv, const JSHandle &obj, const DataViewType arrayType) { ASSERT(argv); @@ -321,7 +321,7 @@ JSTaggedValue TypedArrayHelper::FastCopyElementFromArray( RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle targetObj = JSHandle::Cast(obj); - JSStableArray::FastCopyFromArrayToTypedArray( + JSStableArray::CopyArrayToTypedArrayForCtor( thread, targetObj, arrayType, 0, len, argObj); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSHandle::Cast(targetObj).GetTaggedValue(); diff --git a/ecmascript/base/typed_array_helper.h b/ecmascript/base/typed_array_helper.h index 49ad15a48e..fd51dfd7f0 100644 --- a/ecmascript/base/typed_array_helper.h +++ b/ecmascript/base/typed_array_helper.h @@ -131,7 +131,7 @@ private: const JSHandle &obj, const DataViewType arrayType); template - static JSTaggedValue FastCopyElementFromArray(EcmaRuntimeCallInfo *argv, const JSHandle &obj, + static JSTaggedValue FastCopyElementFromArrayForCtor(EcmaRuntimeCallInfo *argv, const JSHandle &obj, const DataViewType arrayType); }; } // namespace panda::ecmascript::base diff --git a/ecmascript/compiler/builtins/builtins_typedarray_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_typedarray_stub_builder.cpp index 0990d87313..48192ae2b8 100644 --- a/ecmascript/compiler/builtins/builtins_typedarray_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_typedarray_stub_builder.cpp @@ -3465,7 +3465,7 @@ void BuiltinsTypedArrayStubBuilder::FastCopyElementFromArray(Variable *result, G Bind(©Elements); { Label check(env); - FastCopyFromArrayToTypedArray(glue, array, result, Int32(0), len, &check, slowPath, arrayType, true); + CopyArrayToTypedArrayForCtor(glue, array, result, Int32(0), len, &check, slowPath, arrayType, true); Bind(&check); BRANCH(HasPendingException(glue), &hasException, exit); } @@ -3476,13 +3476,13 @@ void BuiltinsTypedArrayStubBuilder::FastCopyElementFromArray(Variable *result, G } } -void BuiltinsTypedArrayStubBuilder::FastCopyFromArrayToTypedArray(GateRef glue, GateRef array, Variable *result, +void BuiltinsTypedArrayStubBuilder::CopyArrayToTypedArrayForCtor(GateRef glue, GateRef array, Variable *result, GateRef targetOffset, GateRef srcLength, Label *check, Label *slowPath, const DataViewType arrayType, bool typedArrayFromCtor) { if (arrayType == DataViewType::UINT8_CLAMPED || arrayType == DataViewType::BIGINT64 || arrayType == DataViewType::BIGUINT64) { - CallRuntimeWithGlobalEnv(glue, GetCurrentGlobalEnv(), RTSTUB_ID(FastCopyFromArrayToTypedArray), + CallRuntimeWithGlobalEnv(glue, GetCurrentGlobalEnv(), RTSTUB_ID(CopyArrayToTypedArrayForCtor), { result->ReadVariable(), IntToTaggedInt(srcLength), array }); Jump(check); return; @@ -3537,6 +3537,8 @@ void BuiltinsTypedArrayStubBuilder::CopyElementsToArrayBuffer(GateRef glue, Gate Label exit(env); Label copyElement(env); GateRef elementsArray = GetElementsArray(glue, array); + NewObjectStubBuilder newBuilder(this); + GateRef copyElements = newBuilder.CopyArray(glue, elementsArray, srcLength, srcLength); GateRef elementSize = Int32(base::TypedArrayHelper::GetSizeFromType(arrayType)); Jump(&loopHead); LoopBegin(&loopHead); @@ -3546,7 +3548,7 @@ void BuiltinsTypedArrayStubBuilder::CopyElementsToArrayBuffer(GateRef glue, Gate Bind(&storeValue); { GateRef value = getWithKind ? GetTaggedValueWithElementsKind(glue, array, *i) - : GetValueFromTaggedArray(glue, elementsArray, *i); + : GetValueFromTaggedArray(glue, copyElements, *i); GateRef val = ToNumber(glue, value); BRANCH(HasPendingException(glue), &exit, ©Element); Bind(©Element); diff --git a/ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h b/ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h index 8f35b1a2c4..5391ea707d 100644 --- a/ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h @@ -70,7 +70,7 @@ public: GateRef GetOnHeapHclassFromType(GateRef glue, GateRef objHclass, const DataViewType arrayType); void FastCopyElementFromArray(Variable *result, GateRef glue, GateRef array, Label *exit, Label *slowPath, const DataViewType arrayType); - void FastCopyFromArrayToTypedArray(GateRef glue, GateRef array, Variable *result, + void CopyArrayToTypedArrayForCtor(GateRef glue, GateRef array, Variable *result, GateRef targetOffset, GateRef srcLength, Label *check, Label *slowPath, const DataViewType arrayType, bool typedArrayFromCtor); void CopyElementsToArrayBuffer(GateRef glue, GateRef srcLength, GateRef array, diff --git a/ecmascript/js_stable_array.cpp b/ecmascript/js_stable_array.cpp index 764311ea49..495d425814 100644 --- a/ecmascript/js_stable_array.cpp +++ b/ecmascript/js_stable_array.cpp @@ -1498,6 +1498,84 @@ JSTaggedValue JSStableArray::FastCopyFromArrayToTypedArray(JSThread *thread, JSH return JSTaggedValue::Undefined(); } +template JSTaggedValue JSStableArray::CopyArrayToTypedArrayForCtor( + JSThread *thread, JSHandle &targetArray, DataViewType targetType, + uint64_t targetOffset, uint32_t srcLength, JSHandle &obj); +template JSTaggedValue JSStableArray::CopyArrayToTypedArrayForCtor( + JSThread *thread, JSHandle &targetArray, DataViewType targetType, + uint64_t targetOffset, uint32_t srcLength, JSHandle &obj); + +template +JSTaggedValue JSStableArray::CopyArrayToTypedArrayForCtor(JSThread *thread, JSHandle &targetArray, + DataViewType targetType, uint64_t targetOffset, + uint32_t srcLength, JSHandle &obj) +{ + JSHandle targetBuffer(thread, targetArray->GetViewedArrayBufferOrByteArray(thread)); + // If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception. + if (BuiltinsArrayBufferType::Type::IsDetachedBuffer(thread, targetBuffer.GetTaggedValue())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.", + JSTaggedValue::Exception()); + } + uint32_t targetLength = targetArray->GetArrayLength(); + uint32_t targetByteOffset = targetArray->GetByteOffset(); + uint32_t targetElementSize = TypedArrayHelper::GetSizeFromType(targetType); + if (srcLength + targetOffset > targetLength) { + THROW_RANGE_ERROR_AND_RETURN(thread, "The sum of length and targetOffset is greater than targetLength.", + JSTaggedValue::Exception()); + } + uint32_t targetByteIndex = static_cast(targetOffset * targetElementSize + targetByteOffset); + ContentType contentType = targetArray->GetContentType(); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle elements(thread, obj->GetElements(thread)); + uint32_t elemLen = elements->GetLength(); + if (contentType == ContentType::BigInt) { + JSHandle copyElememts = factory->CopyArray(elements, elemLen, elemLen); + JSMutableHandle kValue(thread, JSTaggedValue::Hole()); + JSMutableHandle elem(thread, JSTaggedValue::Hole()); + for (uint32_t i = 0; i < srcLength; i++) { + if (i < elemLen) { + elem.Update(copyElememts->Get(thread, i)); // consider element kind + } else { + elem.Update(JSTaggedValue::Hole()); + } + kValue.Update(JSTaggedValue::ToBigInt(thread, elem)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + BuiltinsArrayBufferType::Type::SetValueInBuffer( + thread, targetBuffer.GetTaggedValue(), targetByteIndex, targetType, kValue, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + targetByteIndex += targetElementSize; + } + } else { + double val = 0.0; + uint32_t copyLen = srcLength > elemLen ? elemLen : srcLength; + // only copy elements within copyLen + JSHandle copyElememts = factory->CopyArray(elements, copyLen, copyLen); + for (uint32_t i = 0; i < copyLen; i++) { + JSTaggedValue taggedVal = copyElememts->Get(thread, i); // consider element kind + if (!taggedVal.IsNumber()) { + JSTaggedNumber taggedNumber = JSTaggedValue::ToNumber(thread, taggedVal); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + val = taggedNumber.GetNumber(); + } else { + val = taggedVal.GetNumber(); + } + BuiltinsArrayBufferType::Type::FastSetValueInBuffer( + thread, targetBuffer.GetTaggedValue(), targetByteIndex, targetType, val, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + targetByteIndex += targetElementSize; + } + + for (uint32_t i = copyLen; i < srcLength; i++) { + val = JSTaggedNumber(base::NAN_VALUE).GetNumber(); + BuiltinsArrayBufferType::Type::FastSetValueInBuffer( + thread, targetBuffer.GetTaggedValue(), targetByteIndex, targetType, val, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + targetByteIndex += targetElementSize; + } + } + return JSTaggedValue::Undefined(); +} + JSTaggedValue JSStableArray::At(JSHandle receiver, EcmaRuntimeCallInfo *argv) { JSThread *thread = argv->GetThread(); diff --git a/ecmascript/js_stable_array.h b/ecmascript/js_stable_array.h index 149d732b04..c980074e13 100644 --- a/ecmascript/js_stable_array.h +++ b/ecmascript/js_stable_array.h @@ -97,6 +97,10 @@ public: static JSTaggedValue FastCopyFromArrayToTypedArray(JSThread *thread, JSHandle &target, DataViewType targetType, uint64_t targetOffset, uint32_t srcLength, JSHandle &obj); + template + static JSTaggedValue CopyArrayToTypedArrayForCtor(JSThread *thread, JSHandle &target, + DataViewType targetType, uint64_t targetOffset, + uint32_t srcLength, JSHandle &obj); static JSTaggedValue At(JSHandle receiver, EcmaRuntimeCallInfo *argv); static JSTaggedValue At(JSHandle receiver, EcmaRuntimeCallInfo *argv); static JSTaggedValue With(JSThread *thread, JSHandle receiver, diff --git a/ecmascript/stubs/runtime_stub_list.h b/ecmascript/stubs/runtime_stub_list.h index 37675f8da5..a58d0da339 100644 --- a/ecmascript/stubs/runtime_stub_list.h +++ b/ecmascript/stubs/runtime_stub_list.h @@ -418,7 +418,7 @@ namespace panda::ecmascript { V(ModuleNamespaceHasProperty) \ V(JSObjectHasProperty) \ V(HasProperty) \ - V(FastCopyFromArrayToTypedArray) \ + V(CopyArrayToTypedArrayForCtor) \ V(BigIntConstructor) \ V(ObjectPrototypeHasOwnProperty) \ V(ReflectHas) \ diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index 5dd40211a3..232059d9ec 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -3210,13 +3210,13 @@ DEF_RUNTIME_STUBS(TryGetInternString) return RuntimeTryGetInternString(argGlue, string); } -DEF_RUNTIME_STUBS(FastCopyFromArrayToTypedArray) +DEF_RUNTIME_STUBS(CopyArrayToTypedArrayForCtor) { - RUNTIME_STUBS_HEADER(FastCopyFromArrayToTypedArray); + RUNTIME_STUBS_HEADER(CopyArrayToTypedArrayForCtor); JSHandle targetArray = GetHArg(argv, argc, 0); // 0: means the zeroth parameter JSTaggedValue len = GetArg(argv, argc, 1); // 1: param index JSHandle obj = GetHArg(argv, argc, 2); // 2: param index - return JSStableArray::FastCopyFromArrayToTypedArray(thread, targetArray, + return JSStableArray::CopyArrayToTypedArrayForCtor(thread, targetArray, base::TypedArrayHelper::GetType(targetArray), 0, len.GetInt(), obj).GetRawData(); } diff --git a/test/moduletest/typearray/typearray.js b/test/moduletest/typearray/typearray.js index e460d20fc2..ae80768156 100644 --- a/test/moduletest/typearray/typearray.js +++ b/test/moduletest/typearray/typearray.js @@ -1689,4 +1689,20 @@ assert_equal(typedArrEleAssertLengthRes,typedArrEleAssertLengthEqual); assert_equal(Number.isNaN(v2[0]), false); } +{ + let arr = new Array(); + let arr1 = arr; + let fn = function() { + arr1.length = (35); + arr1[(9)] = arr; + arr1.unshift(undefined); + } + arr1.splice((60), 0, {valueOf:fn}); + let v = arr1.valueOf(); + v.length = (254); + v.constructor = undefined; + let uint16Arr = new Uint16Array(arr); + assert_equal(uint16Arr.length, 254); +} + test_end(); \ No newline at end of file -- Gitee