diff --git a/ecmascript/base/array_helper.cpp b/ecmascript/base/array_helper.cpp index 8d85084f27..152fc47eb3 100644 --- a/ecmascript/base/array_helper.cpp +++ b/ecmascript/base/array_helper.cpp @@ -366,9 +366,9 @@ JSTaggedValue ArrayHelper::FlattenIntoArray(JSThread *thread, const JSHandle &thisObj, - int64_t len, const JSHandle &callbackFnHandle, - HolesType holes) +JSHandle ArrayHelper::SortIndexedProperties(JSThread *thread, const JSHandle &thisObj, + int64_t len, const JSHandle &callbackFnHandle, + HolesType holes) { // 1. Let items be a new empty List. JSHandle items(thread->GetEcmaVM()->GetFactory()->NewTaggedArray(len)); @@ -386,33 +386,34 @@ JSTaggedValue ArrayHelper::SortIndexedProperties(JSThread *thread, const JSHandl // ii. Append kValue to items. // e. Set k to k + 1. bool kRead = false; - JSHandle thisObjVal(thisObj); JSMutableHandle pk(thread, JSTaggedValue::Undefined()); + int64_t index = 0; while (k < len) { if (holes == HolesType::SKIP_HOLES) { - pk.Update(JSTaggedValue(k)); - kRead = JSTaggedValue::HasProperty(thread, thisObjVal, pk); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + pk.Update(JSTaggedValue(k)); + kRead = JSTaggedValue::HasProperty(thread, thisObj, pk); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, items); } else { ASSERT(holes == HolesType::READ_THROUGH_HOLES); kRead = true; } if (kRead) { - JSHandle kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - items->Set(thread, k, kValue.GetTaggedValue()); + JSHandle kValue = JSArray::FastGetPropertyByValue(thread, thisObj, k); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, items); + items->Set(thread, index++, kValue.GetTaggedValue()); } ++k; } - JSHandle array(JSArray::CreateArrayFromList(thread, items)); - JSHandle arrayObj = JSHandle::Cast(array); + if (index < k) { + items->Trim(thread, index); + } // 4. Sort items using an implementation-defined sequence of calls to SortCompare. // If any such call returns an abrupt completion, // stop before performing any further calls to SortCompare and return that Completion Record. - JSArray::Sort(thread, arrayObj, callbackFnHandle); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSArray::SortElements(thread, items, callbackFnHandle); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, items); // 5. Return items. - return arrayObj.GetTaggedValue(); + return items; } } // namespace panda::ecmascript::base diff --git a/ecmascript/base/array_helper.h b/ecmascript/base/array_helper.h index cf12a07a82..7417bbd0cf 100644 --- a/ecmascript/base/array_helper.h +++ b/ecmascript/base/array_helper.h @@ -70,9 +70,9 @@ public: const JSHandle &thisObjVal, const FlattenArgs &args, const JSHandle &mapperFunctionHandle, const JSHandle &thisArg); - static JSTaggedValue SortIndexedProperties(JSThread *thread, const JSHandle &thisObj, - int64_t len, const JSHandle &callbackFnHandle, - HolesType holes); + static JSHandle SortIndexedProperties(JSThread *thread, const JSHandle &thisObj, + int64_t len, const JSHandle &callbackFnHandle, + HolesType holes); }; } // namespace panda::ecmascript::base diff --git a/ecmascript/builtins/builtins_array.cpp b/ecmascript/builtins/builtins_array.cpp index e6922fa252..1292422611 100644 --- a/ecmascript/builtins/builtins_array.cpp +++ b/ecmascript/builtins/builtins_array.cpp @@ -2206,62 +2206,23 @@ JSTaggedValue BuiltinsArray::Some(EcmaRuntimeCallInfo *argv) JSTaggedValue BuiltinsArray::Sort(EcmaRuntimeCallInfo *argv) { ASSERT(argv); - BUILTINS_API_TRACE(argv->GetThread(), Array, Sort); JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, Array, Sort); [[maybe_unused]] EcmaHandleScope handleScope(thread); - // 1. Let obj be ToObject(this value). - JSHandle thisHandle = GetThis(argv); - JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - + // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception. JSHandle callbackFnHandle = GetCallArg(argv, 0); if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception()); } - // 2. Let len be ToLength(Get(obj, "length")). - int64_t len = ArrayHelper::GetArrayLength(thread, JSHandle(thisObjHandle)); - // 3. ReturnIfAbrupt(len). + // 2. Let obj be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSMutableHandle presentValue(thread, JSTaggedValue::Undefined()); - JSMutableHandle middleValue(thread, JSTaggedValue::Undefined()); - JSMutableHandle previousValue(thread, JSTaggedValue::Undefined()); - for (int i = 1; i < len; i++) { - int beginIndex = 0; - int endIndex = i; - presentValue.Update(ObjectFastOperator::FastGetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), i)); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - while (beginIndex < endIndex) { - int middleIndex = (beginIndex + endIndex) / 2; // 2 : half - middleValue.Update( - ObjectFastOperator::FastGetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), middleIndex)); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - double compareResult = ArrayHelper::SortCompare(thread, callbackFnHandle, middleValue, presentValue); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - if (compareResult > 0) { - endIndex = middleIndex; - } else { - beginIndex = middleIndex + 1; - } - } - - if (endIndex >= 0 && endIndex < i) { - for (int j = i; j > endIndex; j--) { - previousValue.Update( - ObjectFastOperator::FastGetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), j - 1)); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), j, - previousValue.GetTaggedValue()); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - } - ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), endIndex, - presentValue.GetTaggedValue()); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - } - } - + // Array sort + JSArray::Sort(thread, JSHandle::Cast(thisObjHandle), callbackFnHandle); return thisObjHandle.GetTaggedValue(); } @@ -3064,20 +3025,20 @@ JSTaggedValue BuiltinsArray::ToSorted(EcmaRuntimeCallInfo *argv) // the following steps when called: // a. Return ? CompareArrayElements(x, y, comparefn). // 6. Let sortedList be ? SortIndexedProperties(O, len, SortCompare, read-through-holes). - JSTaggedValue sortedList = ArrayHelper::SortIndexedProperties(thread, thisObjHandle, len, callbackFnHandle, - base::HolesType::READ_THROUGH_HOLES); + JSHandle sortedList = + ArrayHelper::SortIndexedProperties(thread, JSHandle::Cast(thisObjHandle), len, callbackFnHandle, + base::HolesType::READ_THROUGH_HOLES); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSHandle sortedArray(thread, sortedList); //7. Let j be 0. int64_t j = 0; // 8. Repeat, while j < len, // a. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(j)), sortedList[j]). // b. Set j to j + 1. + JSMutableHandle itemValue(thread, JSTaggedValue::Undefined()); while (j < len) { - JSHandle item = JSArray::FastGetPropertyByValue(thread, sortedArray, j); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, j, item); + itemValue.Update(sortedList->Get(j)); + JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, j, itemValue); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); ++j; } diff --git a/ecmascript/js_array.cpp b/ecmascript/js_array.cpp index a9730532b7..5d1c2c4183 100644 --- a/ecmascript/js_array.cpp +++ b/ecmascript/js_array.cpp @@ -24,6 +24,8 @@ #include "ecmascript/object_fast_operator-inl.h" namespace panda::ecmascript { +using base::ArrayHelper; + JSTaggedValue JSArray::LengthGetter([[maybe_unused]] JSThread *thread, const JSHandle &self) { return JSTaggedValue(JSArray::Cast(*self)->GetLength()); @@ -387,30 +389,67 @@ bool JSArray::FastSetPropertyByValue(JSThread *thread, const JSHandle &obj, const JSHandle &fn) +// ecma2024 23.1.3.20 Array.prototype.sort(comparefn) +JSTaggedValue JSArray::Sort(JSThread *thread, const JSHandle &obj, const JSHandle &fn) { - if (!fn->IsUndefined() && !fn->IsCallable()) { - THROW_TYPE_ERROR(thread, "Callable is false"); + ASSERT(fn->IsUndefined() || fn->IsCallable()); + // 3. Let len be ?LengthOfArrayLike(obj). + int64_t len = ArrayHelper::GetArrayLength(thread, obj); + // ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 4. Let SortCompare be a new Abstract Closure with parameters (x, y) that captures comparefn and performs + // the following steps when called: + // a. Return ? CompareArrayElements(x, y, comparefn). + // 5. Let sortedList be ? SortIndexedProperties(O, len, SortCompare, SKIP-HOLES). + JSHandle sortedList = + ArrayHelper::SortIndexedProperties(thread, obj, len, fn, base::HolesType::SKIP_HOLES); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 6. Let itemCount be the number of elements in sortedList. + uint32_t itemCount = sortedList->GetLength(); + + // 7. Let j be 0. + uint32_t j = 0; + // 8. Repeat, while j < itemCount, + // a. Perform ! Set(obj, ! ToString((j)), sortedList[j], true). + // b. Set j to j + 1. + JSMutableHandle item(thread, JSTaggedValue::Undefined()); + while (j < itemCount) { + item.Update(sortedList->Get(j)); + JSArray::FastSetPropertyByValue(thread, obj, j, item); + ASSERT_NO_ABRUPT_COMPLETION(thread); + ++j; + } + // 9. NOTE: The call to SortIndexedProperties in step 5 uses SKIP-HOLES.The remaining indices are deleted to + // preserve the number of holes that were detected and excluded from the sort. + // 10. Repeat, while j < len, + // a. Perform ? DeletePropertyOrThrow(obj, ! ToString((j))). + // b. Set j to j + 1. + while (j < len) { + item.Update(JSTaggedValue(j)); + JSTaggedValue::DeletePropertyOrThrow(thread, obj, item); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + ++j; } - // 2. Let len be ToLength(Get(obj, "length")). - int64_t len = base::ArrayHelper::GetArrayLength(thread, JSHandle(obj)); - // 3. ReturnIfAbrupt(len). - RETURN_IF_ABRUPT_COMPLETION(thread); + return obj.GetTaggedValue(); +} + +void JSArray::SortElements(JSThread *thread, const JSHandle &elements, const JSHandle &fn) +{ + ASSERT(fn->IsUndefined() || fn->IsCallable()); JSMutableHandle presentValue(thread, JSTaggedValue::Undefined()); JSMutableHandle middleValue(thread, JSTaggedValue::Undefined()); JSMutableHandle previousValue(thread, JSTaggedValue::Undefined()); - for (int64_t i = 1; i < len; i++) { - int64_t beginIndex = 0; - int64_t endIndex = i; - presentValue.Update(ObjectFastOperator::FastGetPropertyByIndex(thread, obj.GetTaggedValue(), i)); - RETURN_IF_ABRUPT_COMPLETION(thread); + uint32_t len = elements->GetLength(); + for (uint32_t i = 1; i < len; i++) { + uint32_t beginIndex = 0; + uint32_t endIndex = i; + presentValue.Update(elements->Get(i)); while (beginIndex < endIndex) { - int64_t middleIndex = (beginIndex + endIndex) / 2; // 2 : half - middleValue.Update( - ObjectFastOperator::FastGetPropertyByIndex(thread, obj.GetTaggedValue(), middleIndex)); - RETURN_IF_ABRUPT_COMPLETION(thread); + uint32_t middleIndex = (beginIndex + endIndex) / 2; // 2 : half + middleValue.Update(elements->Get(middleIndex)); int32_t compareResult = base::ArrayHelper::SortCompare(thread, fn, middleValue, presentValue); RETURN_IF_ABRUPT_COMPLETION(thread); if (compareResult > 0) { @@ -421,17 +460,11 @@ void JSArray::Sort(JSThread *thread, const JSHandle &obj, const JSHand } if (endIndex >= 0 && endIndex < i) { - for (int64_t j = i; j > endIndex; j--) { - previousValue.Update( - ObjectFastOperator::FastGetPropertyByIndex(thread, obj.GetTaggedValue(), j - 1)); - RETURN_IF_ABRUPT_COMPLETION(thread); - ObjectFastOperator::FastSetPropertyByIndex(thread, obj.GetTaggedValue(), j, - previousValue.GetTaggedValue()); - RETURN_IF_ABRUPT_COMPLETION(thread); + for (uint32_t j = i; j > endIndex; j--) { + previousValue.Update(elements->Get(j - 1)); + elements->Set(thread, j, previousValue); } - ObjectFastOperator::FastSetPropertyByIndex(thread, obj.GetTaggedValue(), endIndex, - presentValue.GetTaggedValue()); - RETURN_IF_ABRUPT_COMPLETION(thread); + elements->Set(thread, endIndex, presentValue); } } } diff --git a/ecmascript/js_array.h b/ecmascript/js_array.h index 24feaedb65..f16406bfe9 100644 --- a/ecmascript/js_array.h +++ b/ecmascript/js_array.h @@ -91,13 +91,15 @@ public: static bool FastSetPropertyByValue(JSThread *thread, const JSHandle &obj, const JSHandle &key, const JSHandle &value); - static void Sort(JSThread *thread, const JSHandle &obj, const JSHandle &fn); + static JSTaggedValue Sort(JSThread *thread, const JSHandle &obj, const JSHandle &fn); static bool IncludeInSortedValue(JSThread *thread, const JSHandle &obj, const JSHandle &value); static JSHandle ToTaggedArray(JSThread *thread, const JSHandle &obj); static void CheckAndCopyArray(const JSThread *thread, JSHandle obj); static void SetCapacity(JSThread *thread, const JSHandle &array, uint32_t oldLen, uint32_t newLen, bool isNew = false); + static void SortElements(JSThread *thread, const JSHandle &elements, + const JSHandle &fn); }; class TrackInfo : public TaggedObject { diff --git a/ecmascript/module/js_module_namespace.cpp b/ecmascript/module/js_module_namespace.cpp index e7ac8a16e2..c1d14b9b70 100644 --- a/ecmascript/module/js_module_namespace.cpp +++ b/ecmascript/module/js_module_namespace.cpp @@ -45,7 +45,7 @@ JSHandle ModuleNamespace::ModuleNamespaceCreate(JSThread *threa // are ordered as if an Array of the same values had been sorted using // Array.prototype.sort using undefined as comparefn. JSHandle exportsArray = JSArray::CreateArrayFromList(thread, exports); - JSHandle sortedExports = JSHandle::Cast(exportsArray); + JSHandle sortedExports = JSHandle::Cast(exportsArray); JSHandle fn = globalConst->GetHandledUndefined(); JSArray::Sort(thread, sortedExports, fn); // 8. Set M.[[Exports]] to sortedExports. diff --git a/ecmascript/object_fast_operator-inl.h b/ecmascript/object_fast_operator-inl.h index a1132e865a..d67395957b 100644 --- a/ecmascript/object_fast_operator-inl.h +++ b/ecmascript/object_fast_operator-inl.h @@ -479,12 +479,11 @@ JSTaggedValue ObjectFastOperator::FastGetPropertyByValue(JSThread *thread, JSTag return result; } -template // UseHole is only for Array::Sort() which requires Hole order JSTaggedValue ObjectFastOperator::FastGetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index) { INTERPRETER_TRACE(thread, FastGetPropertyByIndex); JSTaggedValue result = ObjectFastOperator::GetPropertyByIndex(thread, receiver, index); - if (result.IsHole() && !UseHole) { + if (result.IsHole()) { return JSTaggedValue::GetProperty(thread, JSHandle(thread, receiver), index).GetValue().GetTaggedValue(); } diff --git a/ecmascript/object_fast_operator.h b/ecmascript/object_fast_operator.h index c4e8c43312..252f24e3e0 100644 --- a/ecmascript/object_fast_operator.h +++ b/ecmascript/object_fast_operator.h @@ -55,7 +55,6 @@ public: static inline JSTaggedValue FastGetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key); - template static inline JSTaggedValue FastGetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index); static inline JSTaggedValue FastParseDate(const EcmaString *str); @@ -105,4 +104,4 @@ private: friend class FastRuntimeStub; }; } // namespace panda::ecmascript -#endif // ECMASCRIPT_OBJECT_FAST_OPERATOR_H \ No newline at end of file +#endif // ECMASCRIPT_OBJECT_FAST_OPERATOR_H diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index ec5fe7d745..2aadee3fa5 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -2579,45 +2579,8 @@ JSTaggedValue RuntimeStubs::RuntimeArraySort(JSThread *thread, JSHandle presentValue(thread, JSTaggedValue::Undefined()); - JSMutableHandle middleValue(thread, JSTaggedValue::Undefined()); - JSMutableHandle previousValue(thread, JSTaggedValue::Undefined()); JSHandle callbackFnHandle(thread, JSTaggedValue::Undefined()); - for (int i = 1; i < len; i++) { - int beginIndex = 0; - int endIndex = i; - presentValue.Update( - ObjectFastOperator::FastGetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), i)); - RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); - while (beginIndex < endIndex) { - int middleIndex = beginIndex + (endIndex - beginIndex) / 2; // 2 : half - middleValue.Update( - ObjectFastOperator::FastGetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), middleIndex)); - RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); - double compareResult = ArrayHelper::SortCompare(thread, callbackFnHandle, middleValue, presentValue); - RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); - if (compareResult > 0) { - endIndex = middleIndex; - } else { - beginIndex = middleIndex + 1; - } - } - - if (endIndex >= 0 && endIndex < i) { - for (int j = i; j > endIndex; j--) { - previousValue.Update( - ObjectFastOperator::FastGetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), j - 1)); - RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); - ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), j, - previousValue.GetTaggedValue()); - RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); - } - ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), endIndex, - presentValue.GetTaggedValue()); - RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); - } - } - + JSArray::Sort(thread, JSHandle::Cast(thisObjHandle), callbackFnHandle); return thisObjHandle.GetTaggedValue(); } diff --git a/test/moduletest/BUILD.gn b/test/moduletest/BUILD.gn index 44b844e613..0caea5a8d0 100644 --- a/test/moduletest/BUILD.gn +++ b/test/moduletest/BUILD.gn @@ -23,6 +23,7 @@ group("ark_js_moduletest") { "arraytoreversed", "arraytospliced", "arraywith", + "arraysort", "arrayprotochange", "assignproxy", "async", @@ -152,6 +153,7 @@ group("ark_asm_test") { "arrayfindlast", "arrayforeach", "arrayjoin", + "arraysort", "arrayprotochange", "asmstackoverflow", "assignproxy", diff --git a/test/moduletest/arraysort/BUILD.gn b/test/moduletest/arraysort/BUILD.gn new file mode 100644 index 0000000000..d1de44a5b0 --- /dev/null +++ b/test/moduletest/arraysort/BUILD.gn @@ -0,0 +1,18 @@ +# Copyright (c) 2023 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_moduletest_action("arraysort") { + deps = [] +} diff --git a/test/moduletest/arraysort/arraysort.js b/test/moduletest/arraysort/arraysort.js new file mode 100644 index 0000000000..bb142be248 --- /dev/null +++ b/test/moduletest/arraysort/arraysort.js @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2023 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. + */ + +class DeepProxy { + constructor(obj, handler) { + return new Proxy(obj, handler); + } +} +class ClassB { + constructor(n) { + this.n = 0; + this.n = n; + } +} + +let nextFreeId = 0; +class ClassA { + constructor(a, b) { + this.a = a; + this.b = new ClassB(b); + this.id = nextFreeId++; + } +} + +// Testing the proxy situation. +let data1 = [new ClassA(1, 10), new ClassA(3, 30), new ClassA(4, 40), new ClassA(2, 20), new ClassA(11, 250)]; +let objHandler1 = new DeepProxy(data1, {}); +print(JSON.stringify(objHandler1)); +objHandler1.sort((a, b) => { + return a.b.n - b.b.n; +}) +print(JSON.stringify(objHandler1)); + +// Testing cases with both proxy and hole. +let data2 = [new ClassA(1, 10), , new ClassA(3, 30), , new ClassA(4, 40), new ClassA(2, 20), new ClassA(11, 250)]; +let objHandler2 = new DeepProxy(data2, { + deleteProperty(target, prop) { + print(`delete ${prop.toString()}`); + return Reflect.deleteProperty(target, prop); + } +}); +objHandler2.sort((a, b) => { + return a.b.n - b.b.n; +}) +print(JSON.stringify(objHandler2)); + +/* + * Test Case Description: + * 1. This use case is used to verify the logical processing order of the binary insertion sorting algorithm. + * 2. If there are any changes to the use case, please confirm if the use case needs to be modified. + */ +let arr1 = [1, 3, 2]; +arr1.sort((a, b) => { + print(`comparing a = ${a}, b = ${b}`); + return a - b; +}); +print(JSON.stringify(arr1)); + +// Modification of objects during the comparison process. +let arr2 = [1, 3, 2]; +arr2.sort((a, b) => { + if (a == 1 || b == 1) { + arr2[0] == 2; + } + return a - b; +}); +print(JSON.stringify(arr2)); + +let arr3 = [1, 3, 2]; +arr3.sort((a, b) => { + if (a == 1 || b == 1) { + arr3[4] == 2; + } + return a - b; +}); +print(JSON.stringify(arr3)); + +// Testing the situation where this is an Object +let obj1 = {0: 1, 1: 3, a: 6, 2: 2, length: 3}; +Array.prototype.sort.call(obj1, (a, b) => { + return a - b; +}); +print(JSON.stringify(obj1)); + +let obj2 = {0: 1, 1: 3, a: 6, 2: 2, length: 3}; +Array.prototype.sort.call(obj2, (a, b) => { + if (a == 1 || b == 1) { + obj2.a = 60; + } + return a - b; +}); +print(obj2.a == 60); +print(JSON.stringify(obj2)); + +let obj3 = {0: 1, 1: 3, a: 6, 2: 2, length: 2}; +Array.prototype.sort.call(obj3, (a, b) => { + return a - b; +}); +print(obj3[1] == 3) +print(JSON.stringify(obj3)); + +let obj4 = {0: 1, 1: 3, a: 6, 3: 2, length: 4}; +Array.prototype.sort.call(obj4, (a, b) => { + return a - b; +}); +print(obj4[2] == 3) +print(JSON.stringify(obj4)); + +// Test if this is a Map type; +let map1 = new Map(); +map1.set(0, 1); +map1.set(1, 3); +map1.set(2, 2); +map1.set("a", 6); +map1.set("length", 3); +Array.prototype.sort.call(map1, (a, b) => { + return a - b; +}); +print(JSON.stringify(map1)); + +let map2 = new Map(); +map2.set(0, 1); +map2.set(1, 3); +map2.set(2, 2); +map2.set("a", 6); +map2.set("length", 3); +Array.prototype.sort.call(map2, (a, b) => { + if (a == 1 || b == 1) { + map2.set("a", 60); + } + return a - b; +}); +print(JSON.stringify(map2)); + +// Test prototype +let child1 = [1, 3, 2]; +let proto1 = [4, 7, 5]; +child1.__proto__ = proto1; +child1.sort((a, b) => { + return a - b; +}); +print(JSON.stringify(child1)); + +let child2 = [1, , 2]; +child2.__proto__ = proto1; +child2.sort((a, b) => { + return a - b; +}); +print(child2.hasOwnProperty('1')); +print(JSON.stringify(child2)); + +let child3 = [1, 3, 2]; +let proto2 = [4, , 5]; +child3.__proto__ = proto2; +child3.sort((a, b) => { + return a - b; +}); +print(JSON.stringify(child3)); + +let child4 = [1, , 2]; +child4.__proto__ = proto2; +child4.sort((a, b) => { + return a - b; +}); +print(child4.hasOwnProperty('2')); +print(JSON.stringify(child4)); diff --git a/test/moduletest/arraysort/expect_output.txt b/test/moduletest/arraysort/expect_output.txt new file mode 100644 index 0000000000..4c36f23159 --- /dev/null +++ b/test/moduletest/arraysort/expect_output.txt @@ -0,0 +1,39 @@ +# Copyright (c) 2023 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. + +[{"a":1,"b":{"n":10},"id":0},{"a":3,"b":{"n":30},"id":1},{"a":4,"b":{"n":40},"id":2},{"a":2,"b":{"n":20},"id":3},{"a":11,"b":{"n":250},"id":4}] +[{"a":1,"b":{"n":10},"id":0},{"a":2,"b":{"n":20},"id":3},{"a":3,"b":{"n":30},"id":1},{"a":4,"b":{"n":40},"id":2},{"a":11,"b":{"n":250},"id":4}] +delete 5 +delete 6 +[{"a":1,"b":{"n":10},"id":5},{"a":2,"b":{"n":20},"id":8},{"a":3,"b":{"n":30},"id":6},{"a":4,"b":{"n":40},"id":7},{"a":11,"b":{"n":250},"id":9},null,null] +comparing a = 1, b = 3 +comparing a = 3, b = 2 +comparing a = 1, b = 2 +[1,2,3] +[1,2,3] +[1,2,3] +{"0":1,"1":2,"2":3,"a":6,"length":3} +true +{"0":1,"1":2,"2":3,"a":60,"length":3} +true +{"0":1,"1":3,"2":2,"a":6,"length":2} +true +{"0":1,"1":2,"2":3,"a":6,"length":4} +{} +{} +[1,2,3] +true +[1,2,7] +[1,2,3] +false +[1,2,5]