mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-23 10:09:54 +00:00
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:
parent
c8a3605237
commit
c420bd1fe9
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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"
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
17
test/aottest/builtin_inlining/String/LocaleCompare/BUILD.gn
Normal file
17
test/aottest/builtin_inlining/String/LocaleCompare/BUILD.gn
Normal 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") {
|
||||||
|
}
|
@ -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();
|
@ -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
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user