mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-27 04:00:37 +00:00
Optimize StableArrayJoin
Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IAYSJT Signed-off-by: hewei <hewei215@huawei.com> Change-Id: I66a095bc5886b9894256699174fdf69f2ef09b2e
This commit is contained in:
parent
dca45d344f
commit
2c6bd650fa
@ -35,6 +35,8 @@ namespace panda::ecmascript {
|
||||
#define ECMASCRIPT_ENABLE_ELEMENTSKIND_ALWAY_GENERIC 0
|
||||
#define ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT 0
|
||||
|
||||
#define ENABLE_NEXT_OPTIMIZATION 1
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define ECMASCRIPT_ENABLE_INTERPRETER_LOG 1
|
||||
#define ECMASCRIPT_ENABLE_RUNTIME_STAT 1
|
||||
|
@ -417,6 +417,199 @@ JSTaggedValue JSStableArray::Shift(JSHandle<JSArray> receiver, EcmaRuntimeCallIn
|
||||
return result->IsHole() ? JSTaggedValue::Undefined() : result.GetTaggedValue();
|
||||
}
|
||||
|
||||
#if ENABLE_NEXT_OPTIMIZATION
|
||||
bool JSStableArray::WorthUseTreeString(uint32_t sepLength, size_t allocateLength, uint32_t len)
|
||||
{
|
||||
if (allocateLength >= TREE_STRING_THRESHOLD) {
|
||||
// if sepLength is 0, means all the elements in treeString is len -1;
|
||||
// otherwise, the num of elements is (len-1)(string in vector) + (len -1)(num of seps)
|
||||
size_t treeStringElementNum = (sepLength == 0) ? (len - 1) : (2 * (len - 1));
|
||||
|
||||
if (treeStringElementNum * TreeEcmaString::SIZE <= allocateLength) {
|
||||
// heuristic: if tree string uses less memory than linestring, it is worth.
|
||||
// In other words, we hope tree string can work for the large strings join.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
JSTaggedValue JSStableArray::JoinUseTreeString(const JSThread *thread, const JSHandle<JSTaggedValue> receiverValue,
|
||||
const JSHandle<EcmaString> sepStringHandle, uint32_t sepLength,
|
||||
Container &arrElements, int elemNum)
|
||||
{
|
||||
// Do not concat the elements one by one, it will make the tree string unbalanced. Concat each element with its
|
||||
// right neighbor first level by level, then the tree string will be balanced as possible.
|
||||
if (sepLength != 0) {
|
||||
for (int k = 0; k < elemNum - 1; k++) {
|
||||
arrElements[k] = JSHandle<EcmaString>(
|
||||
thread, EcmaStringAccessor::Concat(thread->GetEcmaVM(), arrElements[k], sepStringHandle));
|
||||
RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, receiverValue);
|
||||
}
|
||||
}
|
||||
|
||||
while (elemNum > 1) {
|
||||
size_t newNum = (elemNum + 1) / NUM_2;
|
||||
for (size_t i = 0; i < elemNum / NUM_2; ++i) {
|
||||
arrElements[i] = JSHandle<EcmaString>(
|
||||
thread,
|
||||
EcmaStringAccessor::Concat(thread->GetEcmaVM(), arrElements[NUM_2 * i], arrElements[NUM_2 * i + 1])
|
||||
);
|
||||
RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, receiverValue);
|
||||
}
|
||||
if (elemNum % NUM_2 == 1) {
|
||||
arrElements[newNum - 1] = arrElements[elemNum - 1];
|
||||
}
|
||||
elemNum = newNum;
|
||||
}
|
||||
thread->GetCurrentEcmaContext()->JoinStackPopFastPath(receiverValue);
|
||||
return arrElements[0].GetTaggedValue();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
void JSStableArray::ProcessElements(JSThread *thread, JSHandle<JSTaggedValue> receiverValue, uint32_t len,
|
||||
Container &arrElements, bool &isOneByte, uint64_t &allocateLength)
|
||||
{
|
||||
JSMutableHandle<JSTaggedValue> elementHandle(thread, JSTaggedValue::Undefined());
|
||||
JSHandle<JSObject> obj(thread, receiverValue.GetTaggedValue());
|
||||
JSTaggedValue element = JSTaggedValue::Undefined();
|
||||
for (uint32_t k = 0; k < len; k++) {
|
||||
element = ElementAccessor::Get(obj, k);
|
||||
if (element.IsHole() && JSTaggedValue::HasProperty(thread, receiverValue, k)) {
|
||||
element = JSArray::FastGetPropertyByValue(thread, receiverValue, k).GetTaggedValue();
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
}
|
||||
if (!element.IsUndefinedOrNull() && !element.IsHole()) {
|
||||
if (!element.IsString()) {
|
||||
elementHandle.Update(element);
|
||||
JSHandle<EcmaString> strElement = JSTaggedValue::ToString(thread, elementHandle);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
element = strElement.GetTaggedValue();
|
||||
}
|
||||
auto nextStr = EcmaString::Cast(element.GetTaggedObject());
|
||||
arrElements[k] = JSHandle<EcmaString>(thread, nextStr);
|
||||
isOneByte = isOneByte & EcmaStringAccessor(nextStr).IsUtf8();
|
||||
allocateLength += EcmaStringAccessor(nextStr).GetLength();
|
||||
} else {
|
||||
arrElements[k] = JSHandle<EcmaString>(thread->GlobalConstants()->GetHandledEmptyString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
JSTaggedValue JSStableArray::DoStableArrayJoin(JSThread *thread, JSHandle<JSTaggedValue> receiverValue, uint32_t len,
|
||||
Container &arrElements, bool &isOneByte, uint32_t sep,
|
||||
uint32_t sepLength, JSHandle<EcmaString> sepStringHandle)
|
||||
{
|
||||
auto context = thread->GetCurrentEcmaContext();
|
||||
uint64_t allocateLength = 0;
|
||||
ProcessElements(thread, receiverValue, len, arrElements, isOneByte, allocateLength);
|
||||
RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, receiverValue);
|
||||
|
||||
if (len > 0) {
|
||||
allocateLength += static_cast<uint64_t>(sepLength) * (len - 1);
|
||||
}
|
||||
if (allocateLength > EcmaString::MAX_STRING_LENGTH) {
|
||||
context->JoinStackPopFastPath(receiverValue);
|
||||
THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid string length", JSTaggedValue::Exception());
|
||||
}
|
||||
if (WorthUseTreeString(sepLength, allocateLength, len)) {
|
||||
return JoinUseTreeString(thread, receiverValue, sepStringHandle, sepLength, arrElements, len);
|
||||
}
|
||||
|
||||
// 5. Let R be the empty String.
|
||||
auto newString =
|
||||
EcmaStringAccessor::CreateLineString(thread->GetEcmaVM(), static_cast<size_t>(allocateLength), isOneByte);
|
||||
int current = 0;
|
||||
DISALLOW_GARBAGE_COLLECTION;
|
||||
// 6. Repeat, while k < len
|
||||
for (uint32_t k = 0; k < len; k++) {
|
||||
// a. If k > 0, set R to the string-concatenation of R and sep.
|
||||
if (k > 0) {
|
||||
if (sepLength == 1) {
|
||||
EcmaStringAccessor(newString).Set(current, static_cast<uint16_t>(sep));
|
||||
} else if (sepLength > 1) {
|
||||
EcmaStringAccessor::ReadData(newString, *sepStringHandle, current,
|
||||
allocateLength - static_cast<uint32_t>(current), sepLength);
|
||||
}
|
||||
current += static_cast<int>(sepLength);
|
||||
}
|
||||
// b. Let element be ? Get(O, ToString(𝔽(k))).
|
||||
JSHandle<EcmaString> nextStr = arrElements[k];
|
||||
|
||||
// c. Set R to the string-concatenation of R and S
|
||||
int nextLength = static_cast<int>(EcmaStringAccessor(nextStr).GetLength());
|
||||
EcmaStringAccessor::ReadData(newString, *nextStr, current, allocateLength - static_cast<uint32_t>(current),
|
||||
nextLength);
|
||||
current += nextLength;
|
||||
}
|
||||
ASSERT_PRINT(isOneByte == EcmaStringAccessor::CanBeCompressed(newString),
|
||||
"isOneByte does not match the real value!");
|
||||
context->JoinStackPopFastPath(receiverValue);
|
||||
// return R
|
||||
return JSTaggedValue(newString);
|
||||
}
|
||||
|
||||
JSTaggedValue JSStableArray::Join(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv)
|
||||
{
|
||||
JSThread *thread = argv->GetThread();
|
||||
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
||||
auto context = thread->GetCurrentEcmaContext();
|
||||
|
||||
// 1. Let O be ToObject(this.value)
|
||||
JSHandle<JSTaggedValue> receiverValue = JSHandle<JSTaggedValue>::Cast(receiver);
|
||||
JSHandle<JSObject> obj(thread, receiverValue.GetTaggedValue());
|
||||
|
||||
// 2. Let len be ToLength(Get(O, "length"))
|
||||
uint32_t len = receiver->GetArrayLength();
|
||||
|
||||
int sep = ',';
|
||||
uint32_t sepLength = 1;
|
||||
JSHandle<JSTaggedValue> sepHandle = base::BuiltinsBase::GetCallArg(argv, 0);
|
||||
JSHandle<EcmaString> sepStringHandle;
|
||||
if (sepHandle->IsUndefined()) {
|
||||
// 3. If separator is undefined, let sep be ",".
|
||||
sepHandle = globalConst->GetHandledCommaString();
|
||||
sepStringHandle = JSTaggedValue::ToString(thread, sepHandle);
|
||||
RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, receiverValue);
|
||||
} else {
|
||||
// 4. Else, let sep be ? ToString(separator).
|
||||
sepStringHandle = JSTaggedValue::ToString(thread, sepHandle);
|
||||
RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, receiverValue);
|
||||
sepLength = EcmaStringAccessor(sepStringHandle).GetLength();
|
||||
if (sepLength == 1) {
|
||||
sep = EcmaStringAccessor(sepStringHandle).Get(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool isOneByte = EcmaStringAccessor(sepStringHandle).IsUtf8();
|
||||
|
||||
// Fastpath should put after parsing "sep". Error may occur if sep cannout be transformed to string,
|
||||
// which should be handled before fastpath return.
|
||||
if (len == 0) {
|
||||
context->JoinStackPopFastPath(receiverValue);
|
||||
return globalConst->GetEmptyString();
|
||||
}
|
||||
|
||||
if (len == 1) {
|
||||
// sep unused, set isOneByte to default(true)
|
||||
isOneByte = true;
|
||||
}
|
||||
|
||||
// Use stack memory if the number of elements is less than USE_STACK_MEMORY_THRESHOLD.
|
||||
// arr can be faster then vector.
|
||||
if (len <= USE_STACK_MEMORY_THRESHOLD) {
|
||||
std::array<JSHandle<EcmaString>, USE_STACK_MEMORY_THRESHOLD> arr;
|
||||
return DoStableArrayJoin(thread, receiverValue, len, arr, isOneByte, sep, sepLength, sepStringHandle);
|
||||
} else {
|
||||
CVector<JSHandle<EcmaString>> vec(len);
|
||||
return DoStableArrayJoin(thread, receiverValue, len, vec, isOneByte, sep, sepLength, sepStringHandle);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !ENABLE_NEXT_OPTIMIZATION
|
||||
void JSStableArray::SetSepValue(JSHandle<EcmaString> sepStringHandle, int &sep, uint32_t &sepLength)
|
||||
{
|
||||
if (EcmaStringAccessor(sepStringHandle).IsUtf8() && EcmaStringAccessor(sepStringHandle).GetLength() == 1) {
|
||||
@ -446,17 +639,18 @@ bool JSStableArray::WorthUseTreeString(int sep, size_t allocateLength, uint32_t
|
||||
return false;
|
||||
}
|
||||
|
||||
JSTaggedValue JSStableArray::JoinUseTreeString(const JSThread* thread, const JSHandle<JSTaggedValue> receiverValue,
|
||||
JSTaggedValue JSStableArray::JoinUseTreeString(const JSThread *thread,
|
||||
const JSHandle<JSTaggedValue> receiverValue,
|
||||
const JSHandle<EcmaString> sepStringHandle, const int sep,
|
||||
CVector<JSHandle<EcmaString>>& vec)
|
||||
CVector<JSHandle<EcmaString>> &vec)
|
||||
{
|
||||
// Do not concat the elements one by one, it will make the tree string unbalanced. Concat each element with its
|
||||
// right neighbor first level by level, then the tree string will be balanced as possible.
|
||||
if (sep != JSStableArray::SeparatorFlag::MINUS_TWO) {
|
||||
auto last = std::prev(vec.end());
|
||||
for (auto iter = vec.begin(); iter != last; ++iter) {
|
||||
*iter = JSHandle<EcmaString>(
|
||||
thread, EcmaStringAccessor::Concat(thread->GetEcmaVM(), *iter, sepStringHandle));
|
||||
*iter =
|
||||
JSHandle<EcmaString>(thread, EcmaStringAccessor::Concat(thread->GetEcmaVM(), *iter, sepStringHandle));
|
||||
RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, receiverValue);
|
||||
}
|
||||
}
|
||||
@ -551,7 +745,7 @@ JSTaggedValue JSStableArray::Join(JSHandle<JSArray> receiver, EcmaRuntimeCallInf
|
||||
return JoinUseTreeString(thread, receiverValue, sepStringHandle, sep, vec);
|
||||
}
|
||||
auto newString =
|
||||
EcmaStringAccessor::CreateLineString(thread->GetEcmaVM(), static_cast<size_t>(allocateLength), isOneByte);
|
||||
EcmaStringAccessor::CreateLineString(thread->GetEcmaVM(), static_cast<size_t>(allocateLength), isOneByte);
|
||||
int current = 0;
|
||||
DISALLOW_GARBAGE_COLLECTION;
|
||||
for (uint32_t k = 0; k < len; k++) {
|
||||
@ -560,21 +754,22 @@ JSTaggedValue JSStableArray::Join(JSHandle<JSArray> receiver, EcmaRuntimeCallInf
|
||||
EcmaStringAccessor(newString).Set(current, static_cast<uint16_t>(sep));
|
||||
} else if (sep != JSStableArray::SeparatorFlag::MINUS_TWO) {
|
||||
EcmaStringAccessor::ReadData(newString, *sepStringHandle, current,
|
||||
allocateLength - static_cast<uint32_t>(current), sepLength);
|
||||
allocateLength - static_cast<uint32_t>(current), sepLength);
|
||||
}
|
||||
current += static_cast<int>(sepLength);
|
||||
}
|
||||
JSHandle<EcmaString> nextStr = vec[k];
|
||||
int nextLength = static_cast<int>(EcmaStringAccessor(nextStr).GetLength());
|
||||
EcmaStringAccessor::ReadData(newString, *nextStr, current,
|
||||
allocateLength - static_cast<uint32_t>(current), nextLength);
|
||||
EcmaStringAccessor::ReadData(newString, *nextStr, current, allocateLength - static_cast<uint32_t>(current),
|
||||
nextLength);
|
||||
current += nextLength;
|
||||
}
|
||||
ASSERT_PRINT(
|
||||
isOneByte == EcmaStringAccessor::CanBeCompressed(newString), "isOneByte does not match the real value!");
|
||||
ASSERT_PRINT(isOneByte == EcmaStringAccessor::CanBeCompressed(newString),
|
||||
"isOneByte does not match the real value!");
|
||||
context->JoinStackPopFastPath(receiverValue);
|
||||
return JSTaggedValue(newString);
|
||||
}
|
||||
#endif
|
||||
|
||||
JSTaggedValue JSStableArray::HandleFindIndexOfStable(JSThread *thread, JSHandle<JSObject> thisObjHandle,
|
||||
JSHandle<JSTaggedValue> callbackFnHandle,
|
||||
|
@ -26,7 +26,9 @@
|
||||
namespace panda::ecmascript {
|
||||
class JSStableArray {
|
||||
public:
|
||||
#if !ENABLE_NEXT_OPTIMIZATION
|
||||
enum SeparatorFlag : int { MINUS_ONE = -1, MINUS_TWO = -2 };
|
||||
#endif
|
||||
static JSTaggedValue Push(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv);
|
||||
static JSTaggedValue Push(JSHandle<JSSharedArray> receiver, EcmaRuntimeCallInfo *argv);
|
||||
static JSTaggedValue Pop(JSHandle<JSArray> receiver, EcmaRuntimeCallInfo *argv);
|
||||
@ -100,7 +102,6 @@ public:
|
||||
JSHandle<JSTaggedValue> thisArgHandle, int64_t &k);
|
||||
|
||||
private:
|
||||
static void SetSepValue(JSHandle<EcmaString> sepStringHandle, int &sep, uint32_t &sepLength);
|
||||
enum class IndexOfType {
|
||||
IndexOf,
|
||||
LastIndexOf
|
||||
@ -138,15 +139,37 @@ private:
|
||||
static void HandleArray(JSHandle<JSObject> &newArrayHandle, uint32_t &actualDeleteCount,
|
||||
JSThread *thread, uint32_t &start, JSHandle<JSObject> &thisObjHandle,
|
||||
JSHandle<JSTaggedValue> &holeHandle);
|
||||
static JSTaggedValue JoinUseTreeString(const JSThread* thread, JSHandle<JSTaggedValue> receiverValue,
|
||||
JSHandle<EcmaString> sepStringHandle, int sep,
|
||||
CVector<JSHandle<EcmaString>>& vec);
|
||||
|
||||
#if !ENABLE_NEXT_OPTIMIZATION
|
||||
static void SetSepValue(JSHandle<EcmaString> sepStringHandle, int &sep, uint32_t &sepLength);
|
||||
static JSTaggedValue JoinUseTreeString(const JSThread *thread,
|
||||
const JSHandle<JSTaggedValue> receiverValue,
|
||||
const JSHandle<EcmaString> sepStringHandle, const int sep,
|
||||
CVector<JSHandle<EcmaString>> &vec);
|
||||
inline static bool WorthUseTreeString(int sep, size_t allocateLength, uint32_t len);
|
||||
#endif
|
||||
|
||||
// Allocate object larger than 256 need liner search in the free object list,
|
||||
// so try to use tree string when the join result is larger than 256.
|
||||
static constexpr size_t TREE_STRING_THRESHOLD = 256;
|
||||
static constexpr size_t NUM_2 = 2;
|
||||
|
||||
#if ENABLE_NEXT_OPTIMIZATION
|
||||
// When Array length is no more than 64, use array (stack memory) instead of vector to store the elements.
|
||||
static constexpr size_t USE_STACK_MEMORY_THRESHOLD = 64;
|
||||
inline static bool WorthUseTreeString(uint32_t sepLength, size_t allocateLength, uint32_t len);
|
||||
template <typename Container>
|
||||
static void ProcessElements(JSThread *thread, JSHandle<JSTaggedValue> receiverValue, uint32_t len,
|
||||
Container &arrElements, bool &isOneByte, uint64_t &allocateLength);
|
||||
template <typename Container>
|
||||
static JSTaggedValue DoStableArrayJoin(JSThread *thread, JSHandle<JSTaggedValue> receiverValue, uint32_t len,
|
||||
Container &arrElements, bool &isOneByte, uint32_t sep,
|
||||
uint32_t sepLength, JSHandle<EcmaString> sepStringHandle);
|
||||
template <typename Container>
|
||||
static JSTaggedValue JoinUseTreeString(const JSThread *thread, JSHandle<JSTaggedValue> receiverValue,
|
||||
JSHandle<EcmaString> sepStringHandle, uint32_t sepLength,
|
||||
Container &arrElements, int elemNum);
|
||||
#endif
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_JS_STABLE_ARRAY_H
|
||||
|
@ -37,20 +37,32 @@ enum class StableArrayIndex {
|
||||
namespace panda::test {
|
||||
class JSStableArrayTest : public BaseTestWithScope<false> {
|
||||
public:
|
||||
JSHandle<JSTaggedValue> CallJoin(JSHandle<TaggedArray> handleTagArr, std::string& sep, int64_t lengthArr) const
|
||||
JSHandle<JSTaggedValue> CallJoin(JSHandle<TaggedArray> handleTagArr, JSTaggedValue sepValue) const
|
||||
{
|
||||
ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
|
||||
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
|
||||
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
|
||||
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
|
||||
ecmaRuntimeCallInfo->SetCallArg(0,
|
||||
JSHandle<JSTaggedValue>::Cast(objFactory->NewFromStdString(sep)).GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetCallArg(0, sepValue);
|
||||
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
|
||||
JSHandle<JSTaggedValue> handleTagValEcmaStrRet(thread, JSStableArray::Join(handleArr, ecmaRuntimeCallInfo));
|
||||
TestHelper::TearDownFrame(thread, prev);
|
||||
return handleTagValEcmaStrRet;
|
||||
}
|
||||
|
||||
// tests for sep is Undefined
|
||||
JSHandle<JSTaggedValue> CallJoin(JSHandle<TaggedArray> handleTagArr, int64_t lengthArr) const
|
||||
{
|
||||
JSTaggedValue sepValue = JSTaggedValue::Undefined();
|
||||
return CallJoin(handleTagArr, sepValue);
|
||||
}
|
||||
|
||||
JSHandle<JSTaggedValue> CallJoin(JSHandle<TaggedArray> handleTagArr, std::string& sep, int64_t lengthArr) const
|
||||
{
|
||||
ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory();
|
||||
JSTaggedValue sepValue = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromStdString(sep)).GetTaggedValue();
|
||||
return CallJoin(handleTagArr, sepValue);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -501,6 +513,178 @@ HWTEST_F_L0(JSStableArrayTest, Join_StringElements_LargeString3)
|
||||
EXPECT_TRUE(EcmaStringAccessor(handleEcmaStrRet).IsTreeString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: Join_StringElements_Stack
|
||||
* @tc.desc: Use stack to store the preprocessed elements of the source Array.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require:
|
||||
*/
|
||||
HWTEST_F_L0(JSStableArrayTest, Join_StringElements_Stack)
|
||||
{
|
||||
int32_t lengthArr = 32;
|
||||
// tiny string join should not use tree string.
|
||||
ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
|
||||
JSHandle<JSTaggedValue> handleTagValElementEcmaStr(objFactory->NewFromStdString("a"));
|
||||
for (int i = 0; i < lengthArr; i++) {
|
||||
handleTagArr->Set(thread, i, handleTagValElementEcmaStr.GetTaggedValue());
|
||||
}
|
||||
// sep is Undefined
|
||||
JSHandle<JSTaggedValue> handleTagValEcmaStrRet = CallJoin(handleTagArr, lengthArr);
|
||||
JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
|
||||
// 32 x a
|
||||
EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(),
|
||||
"a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a");
|
||||
EXPECT_FALSE(EcmaStringAccessor(handleEcmaStrRet).IsTreeString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: Join_StringElements_Stack1
|
||||
* @tc.desc: Use stack to store the preprocessed elements of the source Array.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require:
|
||||
*/
|
||||
HWTEST_F_L0(JSStableArrayTest, Join_StringElements_Stack1)
|
||||
{
|
||||
int32_t lengthArr = 4;
|
||||
// large string should use tree string.
|
||||
ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
|
||||
// 64 x a
|
||||
JSHandle<JSTaggedValue> handleTagValElementEcmaStr(
|
||||
objFactory->NewFromStdString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
|
||||
for (int i = 0; i < lengthArr; i++) {
|
||||
handleTagArr->Set(thread, i, handleTagValElementEcmaStr.GetTaggedValue());
|
||||
}
|
||||
// sep is Undefined
|
||||
JSHandle<JSTaggedValue> handleTagValEcmaStrRet = CallJoin(handleTagArr, lengthArr);
|
||||
JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
|
||||
EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(),
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
||||
EXPECT_TRUE(EcmaStringAccessor(handleEcmaStrRet).IsTreeString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: Join_StringElements_Vector
|
||||
* @tc.desc: Use vector to store the preprocessed elements of the source Array.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require:
|
||||
*/
|
||||
HWTEST_F_L0(JSStableArrayTest, Join_StringElements_Vector)
|
||||
{
|
||||
int32_t lengthArr = 128;
|
||||
// tiny string join should not use tree string.
|
||||
ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
|
||||
JSHandle<JSTaggedValue> handleTagValElementEcmaStr(objFactory->NewFromStdString("a"));
|
||||
for (int i = 0; i < lengthArr; i++) {
|
||||
handleTagArr->Set(thread, i, handleTagValElementEcmaStr.GetTaggedValue());
|
||||
}
|
||||
// sep is Undefined
|
||||
JSHandle<JSTaggedValue> handleTagValEcmaStrRet = CallJoin(handleTagArr, lengthArr);
|
||||
JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
|
||||
// 128 x a
|
||||
EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(),
|
||||
"a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,"
|
||||
"a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,"
|
||||
"a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,"
|
||||
"a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a");
|
||||
EXPECT_FALSE(EcmaStringAccessor(handleEcmaStrRet).IsTreeString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: Join_StringElements_Vector1
|
||||
* @tc.desc: Use vector to store the preprocessed elements of the source Array.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require:
|
||||
*/
|
||||
HWTEST_F_L0(JSStableArrayTest, Join_StringElements_Vector1)
|
||||
{
|
||||
int32_t lengthArr = 65;
|
||||
std::string sep = "";
|
||||
// large string should use tree string.
|
||||
ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
|
||||
// 40 x a
|
||||
JSHandle<JSTaggedValue> handleTagValElementEcmaStr(
|
||||
objFactory->NewFromStdString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
|
||||
for (int i = 0; i < lengthArr; i++) {
|
||||
handleTagArr->Set(thread, i, handleTagValElementEcmaStr.GetTaggedValue());
|
||||
}
|
||||
JSHandle<JSTaggedValue> handleTagValEcmaStrRet = CallJoin(handleTagArr, sep, lengthArr);
|
||||
JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
|
||||
EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(),
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
||||
EXPECT_TRUE(EcmaStringAccessor(handleEcmaStrRet).IsTreeString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: At
|
||||
* @tc.desc: Create a source Array whose elements are Numbers and an EcmaRuntimeCallInfo, define the first arg of the
|
||||
|
Loading…
Reference in New Issue
Block a user