Optimize Array.sort

Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IB106H?from=project-issue
Signed-off-by: 刘智杰 <liuzhijie9@huawei.com>

Change-Id: If301c6e3bfdff3381475f5728cb072b6bc65b1a6
This commit is contained in:
刘智杰 2024-10-30 18:41:12 +08:00
parent c8a3605237
commit c420bd1fe9
16 changed files with 419 additions and 60 deletions

View File

@ -2374,12 +2374,12 @@ JSTaggedValue BuiltinsArray::Sort(EcmaRuntimeCallInfo *argv)
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// Array sort // Array sort
if (thisHandle->IsStableJSArray(thread) && callbackFnHandle->IsUndefined()) { if (thisHandle->IsStableJSArray(thread)) {
JSStableArray::Sort(thread, thisObjHandle, callbackFnHandle); JSStableArray::Sort(thread, thisHandle, callbackFnHandle);
} else { } else {
JSArray::Sort(thread, JSHandle<JSTaggedValue>::Cast(thisObjHandle), callbackFnHandle); JSArray::Sort(thread, JSHandle<JSTaggedValue>::Cast(thisObjHandle), callbackFnHandle);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
} }
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return thisObjHandle.GetTaggedValue(); return thisObjHandle.GetTaggedValue();
} }

View File

@ -1702,7 +1702,7 @@ JSTaggedValue BuiltinsSharedArray::Sort(EcmaRuntimeCallInfo *argv)
// Array sort // Array sort
if (thisHandle->IsStableJSArray(thread) && callbackFnHandle->IsUndefined()) { if (thisHandle->IsStableJSArray(thread) && callbackFnHandle->IsUndefined()) {
JSStableArray::Sort(thread, thisObjHandle, callbackFnHandle); JSStableArray::Sort(thread, thisHandle, callbackFnHandle);
} else { } else {
JSSharedArray::Sort(thread, JSHandle<JSTaggedValue>::Cast(thisObjHandle), callbackFnHandle); JSSharedArray::Sort(thread, JSHandle<JSTaggedValue>::Cast(thisObjHandle), callbackFnHandle);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);

View File

@ -18,6 +18,7 @@
#include "ecmascript/compiler/aot_snapshot/aot_snapshot_constants.h" #include "ecmascript/compiler/aot_snapshot/aot_snapshot_constants.h"
#include "ecmascript/js_file_path.h" #include "ecmascript/js_file_path.h"
#include "ecmascript/message_string.h"
#include "ecmascript/ohos/framework_helper.h" #include "ecmascript/ohos/framework_helper.h"
#include "ecmascript/ohos/ohos_preload_app_info.h" #include "ecmascript/ohos/ohos_preload_app_info.h"
#include "ecmascript/snapshot/mem/snapshot.h" #include "ecmascript/snapshot/mem/snapshot.h"

View File

@ -510,29 +510,11 @@ bool JSArray::TryFastCreateDataProperty(JSThread *thread, const JSHandle<JSObjec
return true; return true;
} }
// ecma2024 23.1.3.20 Array.prototype.sort(comparefn) JSTaggedValue JSArray::CopySortedListToReceiver(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
JSTaggedValue JSArray::Sort(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &fn) JSHandle<TaggedArray> sortedList, uint32_t len)
{ {
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);
// If len is 0 or 1, no need to sort
if (len == 0 || len == 1) {
return obj.GetTaggedValue();
}
// 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<TaggedArray> 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. // 6. Let itemCount be the number of elements in sortedList.
uint32_t itemCount = sortedList->GetLength(); uint32_t itemCount = sortedList->GetLength();
// 7. Let j be 0. // 7. Let j be 0.
uint32_t j = 0; uint32_t j = 0;
// 8. Repeat, while j < itemCount, // 8. Repeat, while j < itemCount,
@ -556,7 +538,31 @@ JSTaggedValue JSArray::Sort(JSThread *thread, const JSHandle<JSTaggedValue> &obj
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
++j; ++j;
} }
return obj.GetTaggedValue();
}
// ecma2024 23.1.3.20 Array.prototype.sort(comparefn)
JSTaggedValue JSArray::Sort(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &fn)
{
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);
// If len is 0 or 1, no need to sort
if (len == 0 || len == 1) {
return obj.GetTaggedValue();
}
// 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<TaggedArray> sortedList =
ArrayHelper::SortIndexedProperties(thread, obj, len, fn, base::HolesType::SKIP_HOLES);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSArray::CopySortedListToReceiver(thread, obj, sortedList, len);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return obj.GetTaggedValue(); return obj.GetTaggedValue();
} }

View File

@ -109,6 +109,8 @@ public:
SCheckMode sCheckMode = SCheckMode::CHECK); SCheckMode sCheckMode = SCheckMode::CHECK);
static JSTaggedValue Sort(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &fn); static JSTaggedValue Sort(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &fn);
static JSTaggedValue CopySortedListToReceiver(JSThread *thread, const JSHandle<JSTaggedValue> &thisObjVal,
JSHandle<TaggedArray> sortedList, uint32_t len);
static bool IncludeInSortedValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj, static bool IncludeInSortedValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
const JSHandle<JSTaggedValue> &value); const JSHandle<JSTaggedValue> &value);
static JSHandle<TaggedArray> ToTaggedArray(JSThread *thread, const JSHandle<JSTaggedValue> &obj); static JSHandle<TaggedArray> ToTaggedArray(JSThread *thread, const JSHandle<JSTaggedValue> &obj);

View File

@ -679,8 +679,7 @@ bool CharCanFastCompareOrOutOfBounds(EcmaString* string, int stringLength, int i
// 5. If all equal, return equal. // 5. If all equal, return equal.
// 6. Once some chars cannot be fastcompared, use icu. // 6. Once some chars cannot be fastcompared, use icu.
std::optional<UCollationResult> TryFastCompareStrings([[maybe_unused]] const icu::Collator* icuCollator, std::optional<UCollationResult> TryFastCompareStrings(EcmaString* string1, EcmaString* string2,
EcmaString* string1, EcmaString* string2,
int& processedUntilOut) int& processedUntilOut)
{ {
processedUntilOut = 0; processedUntilOut = 0;
@ -719,17 +718,17 @@ std::optional<UCollationResult> TryFastCompareStrings([[maybe_unused]] const icu
} // namespace } // namespace
//StringPiece is similar to std::string_view //StringPiece is similar to std::string_view
icu::StringPiece ToICUStringPiece(const JSHandle<EcmaString>& string, int offset = 0) icu::StringPiece ToICUStringPiece(EcmaString* string, int offset = 0)
{ {
EcmaStringAccessor stringAcc(string); EcmaStringAccessor stringAcc(string);
ASSERT(stringAcc.IsUtf8()); ASSERT(stringAcc.IsUtf8());
ASSERT(!stringAcc.IsTreeString()); ASSERT(!stringAcc.IsTreeString());
return icu::StringPiece(reinterpret_cast<const char*>(EcmaStringAccessor::GetNonTreeUtf8Data(*string)) + offset, return icu::StringPiece(reinterpret_cast<const char*>(EcmaStringAccessor::GetNonTreeUtf8Data(string)) + offset,
static_cast<int>(stringAcc.GetLength()) - offset); static_cast<int>(stringAcc.GetLength()) - offset);
} }
// Convert to a UTF16 string and partially convert to ICUUnicodeString // Convert to a UTF16 string and partially convert to ICUUnicodeString
icu::UnicodeString ToICUUnicodeString(const JSHandle<EcmaString> &string, int offset = 0) icu::UnicodeString ToICUUnicodeString(EcmaString* string, int offset = 0)
{ {
EcmaStringAccessor stringAcc(string); EcmaStringAccessor stringAcc(string);
ASSERT(!stringAcc.IsTreeString()); ASSERT(!stringAcc.IsTreeString());
@ -741,38 +740,22 @@ icu::UnicodeString ToICUUnicodeString(const JSHandle<EcmaString> &string, int of
// short string on stack // short string on stack
UChar shortStringBuffer[shortStringLength]; UChar shortStringBuffer[shortStringLength];
// utf8 is within ascii, std::copy_n from utf8 to utf16 is OK // utf8 is within ascii, std::copy_n from utf8 to utf16 is OK
std::copy_n(EcmaStringAccessor::GetNonTreeUtf8Data(*string) + offset, partialLength, shortStringBuffer); std::copy_n(EcmaStringAccessor::GetNonTreeUtf8Data(string) + offset, partialLength, shortStringBuffer);
return icu::UnicodeString(shortStringBuffer, partialLength); return icu::UnicodeString(shortStringBuffer, partialLength);
} }
CVector<uint16_t> ucharBuffer(partialLength); CVector<uint16_t> ucharBuffer(partialLength);
std::copy_n(EcmaStringAccessor::GetNonTreeUtf8Data(*string) + offset, partialLength, ucharBuffer.begin()); std::copy_n(EcmaStringAccessor::GetNonTreeUtf8Data(string) + offset, partialLength, ucharBuffer.begin());
return icu::UnicodeString(ucharBuffer.data(), partialLength); return icu::UnicodeString(ucharBuffer.data(), partialLength);
} else { } else {
return icu::UnicodeString(EcmaStringAccessor::GetNonTreeUtf16Data(*string) + offset, partialLength); return icu::UnicodeString(EcmaStringAccessor::GetNonTreeUtf16Data(string) + offset, partialLength);
} }
} }
JSTaggedValue JSCollator::CompareStrings(JSThread *thread, const icu::Collator *icuCollator, JSTaggedValue JSCollator::SlowCompareStrings(const icu::Collator *icuCollator,
const JSHandle<EcmaString> &string1, const JSHandle<EcmaString> &string2, EcmaString* flatString1,
[[maybe_unused]]CompareStringsOption csOption) EcmaString* flatString2,
int processedUntil)
{ {
if (*string1 == *string2) {
return JSTaggedValue(UCollationResult::UCOL_EQUAL);
}
// Since Unicode has ignorable characters,
// we cannot return early for 0-length strings.
auto flatString1 = JSHandle<EcmaString>(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), string1));
auto flatString2 = JSHandle<EcmaString>(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), string2));
int processedUntil = 0;
if (csOption == CompareStringsOption::TRY_FAST_PATH) {
auto maybeResult = TryFastCompareStrings(icuCollator, *flatString1, *flatString2, processedUntil);
if (maybeResult.has_value()) {
return JSTaggedValue(maybeResult.value());
}
}
UCollationResult result; UCollationResult result;
UErrorCode status = U_ZERO_ERROR; UErrorCode status = U_ZERO_ERROR;
if (EcmaStringAccessor(flatString1).IsUtf8() && EcmaStringAccessor(flatString2).IsUtf8()) { if (EcmaStringAccessor(flatString1).IsUtf8() && EcmaStringAccessor(flatString2).IsUtf8()) {
@ -790,7 +773,58 @@ JSTaggedValue JSCollator::CompareStrings(JSThread *thread, const icu::Collator *
auto uString2 = ToICUUnicodeString(flatString2, processedUntil); auto uString2 = ToICUUnicodeString(flatString2, processedUntil);
result = icuCollator->compare(uString1, uString2, status); result = icuCollator->compare(uString1, uString2, status);
ASSERT(U_SUCCESS(status)); ASSERT(U_SUCCESS(status));
return JSTaggedValue(result); return JSTaggedValue(result);
} }
JSTaggedValue JSCollator::CompareStrings(JSThread *thread, const icu::Collator *icuCollator,
const JSHandle<EcmaString> &string1, const JSHandle<EcmaString> &string2,
[[maybe_unused]]CompareStringsOption csOption)
{
if (*string1 == *string2) {
return JSTaggedValue(UCollationResult::UCOL_EQUAL);
}
// Since Unicode has ignorable characters,
// we cannot return early for 0-length strings.
auto flatString1 = JSHandle<EcmaString>(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), string1));
auto flatString2 = JSHandle<EcmaString>(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), string2));
int processedUntil = 0;
if (csOption == CompareStringsOption::TRY_FAST_PATH) {
auto maybeResult = TryFastCompareStrings(*flatString1, *flatString2, processedUntil);
if (maybeResult.has_value()) {
return JSTaggedValue(maybeResult.value());
}
}
return SlowCompareStrings(icuCollator, *flatString1, *flatString2, processedUntil);
}
JSTaggedValue JSCollator::FastCachedCompareStrings(JSThread *thread, JSHandle<JSTaggedValue> locales,
const JSHandle<EcmaString> &string1,
const JSHandle<EcmaString> &string2,
CompareStringsOption csOption)
{
if (*string1 == *string2) {
return JSTaggedValue(UCollationResult::UCOL_EQUAL);
}
// Since Unicode has ignorable characters,
// we cannot return early for 0-length strings.
auto flatString1 = JSHandle<EcmaString>(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), string1));
auto flatString2 = JSHandle<EcmaString>(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), string2));
int processedUntil = 0;
if (csOption == CompareStringsOption::TRY_FAST_PATH) {
auto maybeResult = TryFastCompareStrings(*flatString1, *flatString2, processedUntil);
if (maybeResult.has_value()) {
return JSTaggedValue(maybeResult.value());
}
}
auto icuCollator = JSCollator::GetCachedIcuCollator(thread, locales);
if (icuCollator != nullptr) {
return SlowCompareStrings(icuCollator, *flatString1, *flatString2, processedUntil);
}
return JSTaggedValue::Undefined();
}
} // namespace panda::ecmascript } // namespace panda::ecmascript

View File

@ -122,6 +122,16 @@ public:
const JSHandle<EcmaString> &string1, const JSHandle<EcmaString> &string2, const JSHandle<EcmaString> &string1, const JSHandle<EcmaString> &string2,
CompareStringsOption csOption = CompareStringsOption::NONE); CompareStringsOption csOption = CompareStringsOption::NONE);
static JSTaggedValue FastCachedCompareStrings(JSThread *thread, JSHandle<JSTaggedValue> locales,
const JSHandle<EcmaString> &string1,
const JSHandle<EcmaString> &string2,
CompareStringsOption csOption = CompareStringsOption::NONE);
static JSTaggedValue SlowCompareStrings(const icu::Collator *icuCollator,
EcmaString* flatString1,
EcmaString* flatString2,
int processedUntil);
private: private:
static CaseFirstOption StringToCaseFirstOption(const std::string &str); static CaseFirstOption StringToCaseFirstOption(const std::string &str);

View File

@ -14,7 +14,7 @@
*/ */
#include "ecmascript/js_stable_array.h" #include "ecmascript/js_stable_array.h"
#include "ecmascript/base/sort_helper.h"
#include "ecmascript/base/typed_array_helper-inl.h" #include "ecmascript/base/typed_array_helper-inl.h"
#include "ecmascript/interpreter/fast_runtime_stub-inl.h" #include "ecmascript/interpreter/fast_runtime_stub-inl.h"
@ -1672,11 +1672,108 @@ JSTaggedValue JSStableArray::Slice(JSThread *thread, JSHandle<JSObject> thisObjH
return arrayObj.GetTaggedValue(); return arrayObj.GetTaggedValue();
} }
JSTaggedValue JSStableArray::Sort(JSThread *thread, const JSHandle<JSObject> &thisObj, JSHandle<TaggedArray> JSStableArray::SortIndexedProperties(JSThread *thread, const JSHandle<JSTaggedValue> &thisObjVal,
int64_t len, const JSHandle<JSTaggedValue> &callbackFnHandle,
base::HolesType holes)
{
JSHandle<JSObject> thisObj(thread, thisObjVal.GetTaggedValue());
JSHandle<TaggedArray> elements(thread, thisObj->GetElements());
ElementsKind kind = thisObj->GetClass()->GetElementsKind();
if (!elements->GetClass()->IsMutantTaggedArray()) {
kind = ElementsKind::GENERIC;
}
// 1. fill elements into items.
JSHandle<TaggedArray> items(thread->GetEcmaVM()->GetFactory()->NewTaggedArray(len));
bool kRead = false;
int64_t tmp = 0;
for (int k = 0; k < len; k++) {
JSTaggedValue kValue = ElementAccessor::FastGet(elements, k, kind);
if (holes == base::HolesType::SKIP_HOLES) {
kRead = (kValue != JSTaggedValue::Hole());
} else {
ASSERT(holes == base::HolesType::READ_THROUGH_HOLES);
kRead = true;
}
if (kRead) {
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, items);
items->Set(thread, tmp++, kValue);
}
}
// 2. trim
if (len > tmp) {
items->Trim(thread, tmp);
}
// 3. 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.
base::TimSort::Sort(thread, items, callbackFnHandle);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, items);
// 4. Return items.
return items;
}
JSTaggedValue JSStableArray::CopySortedListToReceiver(JSThread *thread, const JSHandle<JSTaggedValue> &thisObjVal,
JSHandle<TaggedArray> sortedList, uint32_t len)
{
// 6. Let itemCount be the number of elements in sortedList.
uint32_t itemCount = sortedList->GetLength();
// grow elements if len > newLength.
JSHandle<JSObject> thisObj(thisObjVal);
uint32_t newLength = std::max(JSHandle<JSArray>::Cast(thisObjVal)->GetArrayLength(), itemCount);
TaggedArray *elements = TaggedArray::Cast(thisObj->GetElements().GetTaggedObject());
if (newLength > ElementAccessor::GetElementsLength(thisObj)) {
elements = *JSObject::GrowElementsCapacity(thread, thisObj, newLength, true);
}
JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
bool needTransition = true;
// 7. Let j be 0.
// 8. Repeat, while j < itemCount,
// a. Perform ! Set(obj, ! ToString((j)), sortedList[j], true).
// b. Set j to j + 1.
for (int j = 0; j < itemCount; j++) {
valueHandle.Update(sortedList->Get(j));
ElementAccessor::Set(thread, thisObj, j, valueHandle, needTransition);
}
// 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.
valueHandle.Update(JSTaggedValue::Hole());
for (int j = itemCount; j < len; j++) {
ElementAccessor::Set(thread, thisObj, j, valueHandle, needTransition);
}
JSHandle<JSArray>::Cast(thisObj)->SetArrayLength(thread, newLength);
return thisObj.GetTaggedValue();
}
JSTaggedValue JSStableArray::Sort(JSThread *thread, const JSHandle<JSTaggedValue> &thisObjVal,
const JSHandle<JSTaggedValue> &callbackFnHandle) const JSHandle<JSTaggedValue> &callbackFnHandle)
{ {
JSArray::SortElementsByObject(thread, thisObj, callbackFnHandle); // 3. Let len be ?LengthOfArrayLike(obj).
return thisObj.GetTaggedValue(); uint32_t len = JSHandle<JSArray>::Cast(thisObjVal)->GetArrayLength();
// ReturnIfAbrupt(len).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// If len is 0 or 1, no need to sort
if (len == 0 || len == 1) {
return thisObjVal.GetTaggedValue();
}
if (callbackFnHandle->IsUndefined()) {
JSArray::SortElementsByObject(thread, JSHandle<JSObject>::Cast(thisObjVal), callbackFnHandle);
return thisObjVal.GetTaggedValue();
}
JSHandle<TaggedArray> sortedList = JSStableArray::SortIndexedProperties(
thread, thisObjVal, len, callbackFnHandle, base::HolesType::SKIP_HOLES);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (thisObjVal->IsStableJSArray(thread)) {
CopySortedListToReceiver(thread, thisObjVal, sortedList, len);
} else {
JSArray::CopySortedListToReceiver(thread, thisObjVal, sortedList, len);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
return thisObjVal.GetTaggedValue();
} }
JSTaggedValue JSStableArray::Fill(JSThread *thread, const JSHandle<JSObject> &thisObj, JSTaggedValue JSStableArray::Fill(JSThread *thread, const JSHandle<JSObject> &thisObj,

View File

@ -16,6 +16,7 @@
#ifndef ECMASCRIPT_JS_STABLE_ARRAY_H #ifndef ECMASCRIPT_JS_STABLE_ARRAY_H
#define ECMASCRIPT_JS_STABLE_ARRAY_H #define ECMASCRIPT_JS_STABLE_ARRAY_H
#include "ecmascript/base/array_helper.h"
#include "ecmascript/base/typed_array_helper.h" #include "ecmascript/base/typed_array_helper.h"
#include "ecmascript/js_array.h" #include "ecmascript/js_array.h"
#include "ecmascript/js_dataview.h" #include "ecmascript/js_dataview.h"
@ -86,9 +87,13 @@ public:
JSHandle<JSTaggedValue> callbackFnHandle, JSHandle<JSTaggedValue> callbackFnHandle,
JSMutableHandle<JSTaggedValue> accumulator, int64_t &k, int64_t &len); JSMutableHandle<JSTaggedValue> accumulator, int64_t &k, int64_t &len);
static JSTaggedValue Slice(JSThread *thread, JSHandle<JSObject> thisObjHandle, int64_t &k, int64_t &count); static JSTaggedValue Slice(JSThread *thread, JSHandle<JSObject> thisObjHandle, int64_t &k, int64_t &count);
static JSHandle<TaggedArray> SortIndexedProperties(JSThread *thread, const JSHandle<JSTaggedValue> &thisObj,
static JSTaggedValue Sort(JSThread *thread, const JSHandle<JSObject> &thisObj, int64_t len, const JSHandle<JSTaggedValue> &callbackFnHandle,
base::HolesType holes);
static JSTaggedValue Sort(JSThread *thread, const JSHandle<JSTaggedValue> &thisObjVal,
const JSHandle<JSTaggedValue> &callbackFnHandle); const JSHandle<JSTaggedValue> &callbackFnHandle);
static JSTaggedValue CopySortedListToReceiver(JSThread *thread, const JSHandle<JSTaggedValue> &thisObjVal,
JSHandle<TaggedArray> sortedList, uint32_t len);
static JSTaggedValue Fill(JSThread *thread, const JSHandle<JSObject> &thisObj, static JSTaggedValue Fill(JSThread *thread, const JSHandle<JSObject> &thisObj,
const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &value,
int64_t start, int64_t end, int64_t len); int64_t start, int64_t end, int64_t len);

View File

@ -3902,6 +3902,10 @@ DEF_RUNTIME_STUBS(LocaleCompareCacheable)
JSHandle<JSTaggedValue> locales = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter JSHandle<JSTaggedValue> locales = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter
JSHandle<EcmaString> thisHandle = GetHArg<EcmaString>(argv, argc, 1); // 1: means the first parameter JSHandle<EcmaString> thisHandle = GetHArg<EcmaString>(argv, argc, 1); // 1: means the first parameter
JSHandle<EcmaString> thatHandle = GetHArg<EcmaString>(argv, argc, 2); // 2: means the second parameter JSHandle<EcmaString> thatHandle = GetHArg<EcmaString>(argv, argc, 2); // 2: means the second parameter
#if ENABLE_NEXT_OPTIMIZATION
const CompareStringsOption csOption = JSCollator::CompareStringsOptionFor(thread, locales);
JSTaggedValue result = JSCollator::FastCachedCompareStrings(thread, locales, thisHandle, thatHandle, csOption);
#else
auto collator = JSCollator::GetCachedIcuCollator(thread, locales); auto collator = JSCollator::GetCachedIcuCollator(thread, locales);
JSTaggedValue result = JSTaggedValue::Undefined(); JSTaggedValue result = JSTaggedValue::Undefined();
if (collator != nullptr) { if (collator != nullptr) {
@ -3909,6 +3913,7 @@ DEF_RUNTIME_STUBS(LocaleCompareCacheable)
thread, locales); thread, locales);
result = JSCollator::CompareStrings(thread, collator, thisHandle, thatHandle, csOption); result = JSCollator::CompareStrings(thread, collator, thisHandle, thatHandle, csOption);
} }
#endif
return result.GetRawData(); return result.GetRawData();
} }

View File

@ -13,7 +13,10 @@
group("ark_aot_builtin_inlining_String_test") { group("ark_aot_builtin_inlining_String_test") {
testonly = true testonly = true
test_list = [ "CharCodeAt" ] test_list = [
"CharCodeAt",
"LocaleCompare",
]
deps = [] deps = []
foreach(test, test_list) { foreach(test, test_list) {

View File

@ -0,0 +1,17 @@
# Copyright (c) 2024 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_aot_builtin_inlining_test_action("builtinStringLocaleCompare") {
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2024 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.
*/
declare function print(arg:any):string;
function func() {
let a = "hijklmn";
let b = "abcdefg";
//aot: [trace] aot inline function name: #*#func@builtinStringLocaleCompare caller function name: func_main_0@builtinStringLocaleCompare
//: 1
print(a.localeCompare(b));
}
func();

View File

@ -376,3 +376,110 @@ print("sort Test Success!");
array1[0] = `g`; array1[0] = `g`;
print(array1.toSorted()); print(array1.toSorted());
} }
// Test sort if array has hole
function HoleSort()
{
let sortNumber= [];
for (let i = 0; i < 10; i++) {
sortNumber.push(parseInt(i));
}
sortNumber[100] = parseInt(100);
print(sortNumber.length);
print(sortNumber);
sortNumber.sort((a, b) => {
return a < b;
});
print(sortNumber.length);
print(sortNumber);
}
HoleSort();
let sortNumber = [0,3,2,,4,5,6];
sortNumber.sort((a,b) => {
sortNumber[10000] = 1;
return a-b;
});
print(sortNumber.length);
print(sortNumber);
let sortNumber2 = [0,3,2,,4,5,6];
sortNumber2.sort((a,b) => {
sortNumber2[3] = 1;
return a-b;
});
print(sortNumber2.length);
print(sortNumber2);
let sortNumber3 = [0,3,2,,4,5,6];
sortNumber3.sort((a,b) => {
sortNumber3 = 1; // stlexvar
return a-b;
});
print(sortNumber3.length);
print(sortNumber3[0]);
print(sortNumber3[2]);
print(sortNumber3[4]);
print(sortNumber3[6]);
let sortNumber4 = [0,3,2,,4,5,6];
sortNumber4.sort((a,b) => {
sortNumber4.push(1);
return a-b;
});
print(sortNumber4.length);
print(sortNumber4[0]);
print(sortNumber4[2]);
print(sortNumber4[4]);
print(sortNumber4[6]);
let sortNumber5 = [-1, 2, 4, 1, 0];
sortNumber5.sort((x, y) => {
Object.defineProperty(sortNumber5, '2', {
get() {
print("get second element:");
return this.value;
},
set(newValue) {
print("set second element:", newValue);
this.value = newValue;
}
});
return x - y;
})
print(sortNumber5.length);
print(sortNumber5.value);
print(sortNumber5);
let sortNumber6 = [-1, 2, 4, 1, 0];
sortNumber6.sort((x, y) => {
Object.defineProperty(sortNumber6, '100', {
get() {
print("get 10000th element:");
return this.value;
},
set(newValue) {
print("set 10000th element:", newValue);
this.value = newValue;
},
configurable: true // 允许重新定义
});
return x - y;
})
print(sortNumber6.length);
print(sortNumber6.value);
print(sortNumber6);
let sortNumber7 = [0,3,2,,4,5,6];
sortNumber7.sort((a,b) => {
sortNumber7.pop();
return a-b;
});
print(sortNumber7.length);
print(sortNumber7[0]);
print(sortNumber7[2]);
print(sortNumber7[4]);
print(sortNumber7[6]);

File diff suppressed because one or more lines are too long

View File

@ -1613,6 +1613,10 @@ template("host_aot_js_test_action") {
" --aot-file=" + rebase_path(_test_aot_arg_litecg_) + " --aot-file=" + rebase_path(_test_aot_arg_litecg_) +
" --asm-interpreter=true" + " --entry-point=${_target_name_}" " --asm-interpreter=true" + " --entry-point=${_target_name_}"
_icu_data_path_options_ =
" --icu-data-path=" + rebase_path("//third_party/icu/ohos_icu4j/data")
_aot_run_options_ += _icu_data_path_options_
if (defined(invoker.is_enable_enableArkTools) && if (defined(invoker.is_enable_enableArkTools) &&
invoker.is_enable_enableArkTools) { invoker.is_enable_enableArkTools) {
_aot_run_options_ += " --enable-ark-tools=true" _aot_run_options_ += " --enable-ark-tools=true"
@ -1682,6 +1686,10 @@ template("host_aot_js_test_action") {
" --aot-file=" + rebase_path(_test_aot_arg_litecg_) + " --aot-file=" + rebase_path(_test_aot_arg_litecg_) +
" --asm-interpreter=true" + " --entry-point=${_target_name_}" " --asm-interpreter=true" + " --entry-point=${_target_name_}"
_icu_data_path_options_ =
" --icu-data-path=" + rebase_path("//third_party/icu/ohos_icu4j/data")
_aot_run_options_ += _icu_data_path_options_
if (defined(invoker.is_enable_enableArkTools) && if (defined(invoker.is_enable_enableArkTools) &&
invoker.is_enable_enableArkTools) { invoker.is_enable_enableArkTools) {
_aot_run_options_ += " --enable-ark-tools=true" _aot_run_options_ += " --enable-ark-tools=true"
@ -1880,6 +1888,10 @@ template("host_aot_js_test_action") {
" --aot-file=" + rebase_path(_test_aot_arg_litecg_) + " --aot-file=" + rebase_path(_test_aot_arg_litecg_) +
" --asm-interpreter=true" + " --entry-point=${_target_name_}" " --asm-interpreter=true" + " --entry-point=${_target_name_}"
_icu_data_path_options_ =
" --icu-data-path=" + rebase_path("//third_party/icu/ohos_icu4j/data")
_aot_run_options_ += _icu_data_path_options_
if (defined(invoker.is_enable_enableArkTools) && if (defined(invoker.is_enable_enableArkTools) &&
invoker.is_enable_enableArkTools) { invoker.is_enable_enableArkTools) {
_aot_run_options_ += " --enable-ark-tools=true" _aot_run_options_ += " --enable-ark-tools=true"
@ -2513,6 +2525,10 @@ template("host_aot_test_action") {
" --enable-pgo-profiler=true" + " --compiler-pgo-profiler-path=" + " --enable-pgo-profiler=true" + " --compiler-pgo-profiler-path=" +
rebase_path(_test_profiler_path_) rebase_path(_test_profiler_path_)
_icu_data_path_options_ =
" --icu-data-path=" + rebase_path("//third_party/icu/ohos_icu4j/data")
_aot_run_options_ += _icu_data_path_options_
if (defined(invoker.is_enable_enableArkTools) && if (defined(invoker.is_enable_enableArkTools) &&
invoker.is_enable_enableArkTools) { invoker.is_enable_enableArkTools) {
_aot_run_options_ += " --enable-ark-tools=true" _aot_run_options_ += " --enable-ark-tools=true"