* 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.
*/
#include "ecmascript/js_array.h"
#include "ecmascript/global_env.h"
#include "ecmascript/tests/test_helper.h"
using namespace panda::ecmascript;
namespace panda::test {
class BarrierTest : public BaseTestWithScope<true> {
};
HWTEST_F_L0(BarrierTest, YoungToYoungBatchCopy)
{
ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
uint32_t arrayLength = 10;
JSHandle<TaggedArray> srcArray = factory->NewTaggedArray(arrayLength);
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
for (uint32_t i = 0; i < arrayLength; i++) {
JSHandle<JSFunction> newFun = factory->NewJSFunction(env);
srcArray->Set(thread, i, newFun);
}
JSHandle<TaggedArray> dstArray = factory->NewTaggedArray(arrayLength);
std::set<uintptr_t> LocalToShareBeforeCopy;
Region* dstRegion = Region::ObjectAddressToRange(dstArray.GetObject<TaggedArray>());
dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
LocalToShareBeforeCopy.emplace(ToUintPtr(mem));
return true;
});
JSTaggedValue* to = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray->GetData()));
JSTaggedValue* from = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
Barriers::CopyObject<true, false>(thread, *dstArray, to, from, arrayLength);
dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
EXPECT_TRUE(LocalToShareBeforeCopy.count(ToUintPtr(mem)));
return true;
});
for (uint32_t i = 0; i < arrayLength; i++) {
EXPECT_EQ(dstArray->Get(thread, i), srcArray->Get(thread, i));
}
}
HWTEST_F_L0(BarrierTest, BatchCopyNoBarrier)
{
ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
uint32_t arrayLength = 10;
JSHandle<TaggedArray> srcArray = factory->NewTaggedArray(arrayLength);
for (uint32_t i = 0; i < arrayLength; i++) {
srcArray->Set(thread, i, JSTaggedValue(i));
}
JSHandle<TaggedArray> dstArray = factory->NewTaggedArray(arrayLength);
std::set<uintptr_t> LocalToShareBeforeCopy;
Region* dstRegion = Region::ObjectAddressToRange(dstArray.GetObject<TaggedArray>());
dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
LocalToShareBeforeCopy.emplace(ToUintPtr(mem));
return true;
});
JSTaggedValue* to = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray->GetData()));
JSTaggedValue* from = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
Barriers::CopyObject<false, false>(thread, nullptr, to, from, arrayLength);
dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
EXPECT_TRUE(LocalToShareBeforeCopy.count(ToUintPtr(mem)));
return true;
});
for (uint32_t i = 0; i < arrayLength; i++) {
EXPECT_EQ(dstArray->Get(thread, i), srcArray->Get(thread, i));
}
JSHandle<TaggedArray> dstArray2 = factory->NewTaggedArray(arrayLength);
JSTaggedValue* to2 = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray2->GetData()));
JSTaggedValue* from2 = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
Barriers::CopyObject<true, false>(thread, *dstArray, to2, from2, arrayLength);
for (uint32_t i = 0; i < arrayLength; i++) {
EXPECT_EQ(dstArray2->Get(thread, i), srcArray->Get(thread, i));
}
}
HWTEST_F_L0(BarrierTest, LocalToShareBatchCopy)
{
ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
uint32_t arrayLength = 10;
JSHandle<TaggedArray> srcArray = factory->NewTaggedArray(arrayLength);
for (uint32_t i = 0; i < arrayLength; i++) {
JSHandle<EcmaString> str = factory->NewFromStdString(std::to_string(i) + "_" + std::to_string(i));
srcArray->Set(thread, i, str);
}
JSHandle<TaggedArray> dstArray = factory->NewTaggedArray(arrayLength);
std::set<uintptr_t> LocalToShareBeforeCopy;
Region* dstRegion = Region::ObjectAddressToRange(dstArray.GetObject<TaggedArray>());
dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
LocalToShareBeforeCopy.emplace(ToUintPtr(mem));
return true;
});
JSTaggedValue* to = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray->GetData()));
JSTaggedValue* from = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
Barriers::CopyObject<true, false>(thread, *dstArray, to, from, arrayLength);
std::set<uintptr_t> LocalToShareSlot;
for (uint32_t i = 0; i < arrayLength; i++) {
LocalToShareSlot.insert(ToUintPtr(dstArray->GetData() + i));
}
dstRegion->IterateAllLocalToShareBits([&LocalToShareSlot, &LocalToShareBeforeCopy, &dstArray, arrayLength](
void* mem) {
if (!LocalToShareBeforeCopy.count(ToUintPtr(mem))) {
EXPECT_GE(ToUintPtr(mem), ToUintPtr(dstArray->GetData()));
EXPECT_LT(ToUintPtr(mem), ToUintPtr(dstArray->GetData()+arrayLength));
LocalToShareSlot.erase(ToUintPtr(mem));
} else {
EXPECT_TRUE(LocalToShareBeforeCopy.count(ToUintPtr(mem)));
}
return true;
});
EXPECT_TRUE(LocalToShareSlot.empty());
for (uint32_t i = 0; i < arrayLength; i++) {
EXPECT_EQ(dstArray->Get(thread, i), srcArray->Get(thread, i));
}
}
HWTEST_F_L0(BarrierTest, LocalToReadOnlyShareBatchCopy)
{
ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
uint32_t arrayLength = 10;
JSHandle<TaggedArray> srcArray = factory->NewTaggedArray(arrayLength);
for (uint32_t i = 0; i < arrayLength; i++) {
JSHandle<EcmaString> str = factory->NewFromStdString(std::to_string(i));
srcArray->Set(thread, i, str);
}
JSHandle<TaggedArray> dstArray = factory->NewTaggedArray(arrayLength);
std::set<uintptr_t> LocalToShareBeforeCopy;
Region* dstRegion = Region::ObjectAddressToRange(dstArray.GetObject<TaggedArray>());
dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
LocalToShareBeforeCopy.emplace(ToUintPtr(mem));
return true;
});
JSTaggedValue* to = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray->GetData()));
JSTaggedValue* from = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
Barriers::CopyObject<true, false>(thread, *dstArray, to, from, arrayLength);
std::set<uintptr_t> LocalToShareSlot;
for (uint32_t i = 0; i < arrayLength; i++) {
LocalToShareSlot.insert(ToUintPtr(dstArray->GetData() + i));
}
dstRegion->IterateAllLocalToShareBits([&LocalToShareSlot, &LocalToShareBeforeCopy](
void* mem) {
EXPECT_FALSE(LocalToShareSlot.count(ToUintPtr(mem)));
EXPECT_TRUE(LocalToShareBeforeCopy.count(ToUintPtr(mem)));
return true;
});
for (uint32_t i = 0; i < arrayLength; i++) {
EXPECT_EQ(dstArray->Get(thread, i), srcArray->Get(thread, i));
}
}
HWTEST_F_L0(BarrierTest, LocalToShareMixBatchCopy)
{
ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
uint32_t arrayLength = 10;
JSHandle<TaggedArray> srcArray = factory->NewTaggedArray(arrayLength);
for (uint32_t i = 0; i < arrayLength; i++) {
if (i % 2 == 0) {
JSHandle<EcmaString> str = factory->NewFromStdString(std::to_string(i) + "_" + std::to_string(i));
srcArray->Set(thread, i, str);
} else {
srcArray->Set(thread, i, JSTaggedValue(i));
}
}
JSHandle<TaggedArray> dstArray = factory->NewTaggedArray(arrayLength);
std::set<uintptr_t> LocalToShareBeforeCopy;
Region* dstRegion = Region::ObjectAddressToRange(dstArray.GetObject<TaggedArray>());
dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
LocalToShareBeforeCopy.emplace(ToUintPtr(mem));
return true;
});
JSTaggedValue* to = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray->GetData()));
JSTaggedValue* from = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
Barriers::CopyObject<true, false>(thread, *dstArray, to, from, arrayLength);
std::set<uintptr_t> LocalToShareSlot;
for (uint32_t i = 0; i < arrayLength; i++) {
if (i % 2 == 0) {
LocalToShareSlot.insert(ToUintPtr(dstArray->GetData() + i));
}
}
dstRegion->IterateAllLocalToShareBits([&LocalToShareSlot, &LocalToShareBeforeCopy, &dstArray, arrayLength](
void* mem) {
if (!LocalToShareBeforeCopy.count(ToUintPtr(mem))) {
EXPECT_GE(ToUintPtr(mem), ToUintPtr(dstArray->GetData()));
EXPECT_LT(ToUintPtr(mem), ToUintPtr(dstArray->GetData()+arrayLength));
LocalToShareSlot.erase(ToUintPtr(mem));
} else {
EXPECT_TRUE(LocalToShareBeforeCopy.count(ToUintPtr(mem)));
}
return true;
});
EXPECT_TRUE(LocalToShareSlot.empty());
for (uint32_t i = 0; i < arrayLength; i++) {
EXPECT_EQ(dstArray->Get(thread, i), srcArray->Get(thread, i));
}
}
HWTEST_F_L0(BarrierTest, OldToNewBatchCopy)
{
if constexpr (G_USE_CMS_GC) {
return;
}
ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
uint32_t arrayLength = 10;
JSHandle<TaggedArray> srcArray = factory->NewOldSpaceTaggedArray(arrayLength);
JSHandle<TaggedArray> dstArray = factory->NewOldSpaceTaggedArray(arrayLength);
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSFunction> newFun = factory->NewJSFunction(env);
for (uint32_t i = 0; i < 10; i++) {
srcArray->Set(thread, i, newFun);
}
std::set<uintptr_t> OldToNewSlot;
for (uint32_t i = 0; i < arrayLength; i++) {
if (Region::ObjectAddressToRange(srcArray->Get(thread, i).GetTaggedObject())->InYoungSpace()) {
OldToNewSlot.insert(ToUintPtr(dstArray->GetData() + i));
}
}
EXPECT_TRUE(!OldToNewSlot.empty());
std::set<uintptr_t> OldToNewBeforeCopy;
std::set<uintptr_t> LocalToShareBeforeCopy;
Region* dstRegion = Region::ObjectAddressToRange(dstArray.GetObject<TaggedArray>());
dstRegion->IterateAllOldToNewBits([&OldToNewBeforeCopy](void* mem) {
OldToNewBeforeCopy.emplace(ToUintPtr(mem));
return true;
});
dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
LocalToShareBeforeCopy.emplace(ToUintPtr(mem));
return true;
});
JSTaggedValue* to = reinterpret_cast<JSTaggedValue*>(ToUintPtr(dstArray->GetData()));
JSTaggedValue* from = reinterpret_cast<JSTaggedValue*>(ToUintPtr(srcArray->GetData()));
Barriers::CopyObject<true, false>(thread, *dstArray, to, from, arrayLength);
dstRegion->IterateAllLocalToShareBits([&LocalToShareBeforeCopy](void* mem) {
EXPECT_TRUE(LocalToShareBeforeCopy.count(ToUintPtr(mem)));
return true;
});
for (uint32_t i = 0; i < arrayLength; i++) {
EXPECT_EQ(dstArray->Get(thread, i), srcArray->Get(thread, i));
}
}
HWTEST_F_L0(BarrierTest, BarrierTest1)
{
common::GCPhase gcPhase;
gcPhase = common::GCPhase::GC_PHASE_ENUM;
EXPECT_TRUE(Barriers::ShouldProcessSATB(gcPhase));
EXPECT_TRUE(Barriers::ShouldGetGCReason(gcPhase));
gcPhase = common::GCPhase::GC_PHASE_START;
EXPECT_FALSE(Barriers::ShouldProcessSATB(gcPhase));
EXPECT_FALSE(Barriers::ShouldGetGCReason(gcPhase));
}
HWTEST_F_L0(BarrierTest, BarrierTest2)
{
common::GCPhase gcPhase;
gcPhase = common::GCPhase::GC_PHASE_START;
EXPECT_TRUE(Barriers::ShouldUpdateRememberSet(gcPhase));
}
HWTEST_F_L0(BarrierTest, BarrierTest3)
{
common::GCPhase gcPhase;
gcPhase = common::GCPhase::GC_PHASE_ENUM;
common::Heap::GetHeap().SetGCReason(common::GC_REASON_YOUNG);
EXPECT_TRUE(Barriers::ShouldUpdateRememberSet(gcPhase));
}
HWTEST_F_L0(BarrierTest, BarrierTest4)
{
common::GCPhase gcPhase;
gcPhase = common::GCPhase::GC_PHASE_START;
common::Heap::GetHeap().SetGCReason(common::GC_REASON_YOUNG);
EXPECT_TRUE(Barriers::ShouldUpdateRememberSet(gcPhase));
}
HWTEST_F_L0(BarrierTest, BarrierTest5)
{
common::GCPhase gcPhase;
gcPhase = common::GCPhase::GC_PHASE_ENUM;
common::Heap::GetHeap().SetGCReason(common::GC_REASON_NATIVE);
EXPECT_FALSE(Barriers::ShouldUpdateRememberSet(gcPhase));
}
}