• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/cross_vm/unified_gc/unified_gc_marker.h"
17 #include "ecmascript/tests/unified_gc_test_helper.h"
18 #include "ecmascript/mem/concurrent_marker.h"
19 #include "ecmascript/mem/region-inl.h"
20 
21 using namespace panda::ecmascript;
22 
23 namespace panda::test {
24 class UnifiedGCTest : public BaseTestWithScope<false> {};
25 
26 class UnifiedGCVerificationTest : public UnifiedGCTest {
27 public:
SetUp()28     void SetUp() override
29     {
30         JSRuntimeOptions options;
31         options.SetArkProperties(options.GetArkProperties() | ArkProperties::ENABLE_HEAP_VERIFY);
32         instance = JSNApi::CreateEcmaVM(options);
33         ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM";
34         thread = instance->GetJSThread();
35         thread->ManagedCodeBegin();
36         scope = new EcmaHandleScope(thread);
37     }
38 };
39 
HWTEST_F_L0(UnifiedGCTest,UnifiedGCMarkRootsScopeTest)40 HWTEST_F_L0(UnifiedGCTest, UnifiedGCMarkRootsScopeTest)
41 {
42     EcmaVM *vm = thread->GetEcmaVM();
43     JSHandle<TaggedArray> weakRefArray = vm->GetFactory()->NewTaggedArray(INT_VALUE_2, JSTaggedValue::Hole());
44     vm->SetEnableForceGC(false);
45     {
46         [[maybe_unused]] EcmaHandleScope ecmaHandleScope(thread);
47         JSHandle<JSTaggedValue> arrayInXRefRoot = JSArray::ArrayCreate(thread, JSTaggedNumber(INT_VALUE_1));
48         JSHandle<JSTaggedValue> arrayInRoot = JSArray::ArrayCreate(thread, JSTaggedNumber(INT_VALUE_1));
49         thread->NewXRefGlobalHandle(arrayInXRefRoot.GetTaggedType());
50         thread->NewGlobalHandle(arrayInRoot.GetTaggedType());
51         weakRefArray->Set(thread, INT_VALUE_0, arrayInXRefRoot.GetTaggedValue().CreateAndGetWeakRef());
52         weakRefArray->Set(thread, INT_VALUE_1, arrayInRoot.GetTaggedValue().CreateAndGetWeakRef());
53     }
54     [[maybe_unused]] UnifiedGCMarkRootsScope unifiedGCMarkRootsScope(thread);
55     vm->CollectGarbage(TriggerGCType::FULL_GC);
56     EXPECT_TRUE(weakRefArray->Get(INT_VALUE_0).IsUndefined());
57     EXPECT_TRUE(!weakRefArray->Get(INT_VALUE_1).IsUndefined());
58     vm->SetEnableForceGC(true);
59 }
60 
61 #ifdef PANDA_JS_ETS_HYBRID_MODE
HWTEST_F_L0(UnifiedGCTest,DoHandshakeTest)62 HWTEST_F_L0(UnifiedGCTest, DoHandshakeTest)
63 {
64     EcmaVM *vm = thread->GetEcmaVM();
65     // Construct fake stsVMInterface and ecmaVMInterface for test, ecmaVMInterface used for STSVM so can be nullptr.
66     auto stsVMInterface = std::make_unique<STSVMInterfaceTest>();
67     void *ecmaVMInterface = nullptr;
68     CrossVMOperator::DoHandshake(vm, stsVMInterface.get(), &ecmaVMInterface);
69 
70     EXPECT_TRUE(vm->GetCrossVMOperator()->GetSTSVMInterface() == stsVMInterface.get());
71     EXPECT_TRUE(vm->GetCrossVMOperator()->GetEcmaVMInterface() ==
72         static_cast<arkplatform::EcmaVMInterface *>(ecmaVMInterface));
73 }
74 
HWTEST_F_L0(UnifiedGCTest,TriggerUnifiedGCMarkTest1)75 HWTEST_F_L0(UnifiedGCTest, TriggerUnifiedGCMarkTest1)
76 {
77     EcmaVM *vm = thread->GetEcmaVM();
78     auto stsVMInterface = std::make_unique<STSVMInterfaceTest>();
79     void *ecmaVMInterface = nullptr;
80     CrossVMOperator::DoHandshake(vm, stsVMInterface.get(), &ecmaVMInterface);
81 
82     CrossReferenceObjectBuilder CrossReferenceObject(vm, thread);
83     SharedHeap::GetInstance()->TriggerUnifiedGCMark<TriggerGCType::UNIFIED_GC, GCReason::CROSSREF_CAUSE>(thread);
84     while (!thread->HasSuspendRequest()) {}
85     thread->WaitSuspension();
86 
87     CrossReferenceObject.CheckResultAfterUnifiedGC();
88 }
89 
HWTEST_F_L0(UnifiedGCTest,TriggerUnifiedGCMarkTest2)90 HWTEST_F_L0(UnifiedGCTest, TriggerUnifiedGCMarkTest2)
91 {
92     EcmaVM *vm = thread->GetEcmaVM();
93     auto stsVMInterface = std::make_unique<STSVMInterfaceTest>();
94     void *ecmaVMInterface = nullptr;
95     CrossVMOperator::DoHandshake(vm, stsVMInterface.get(), &ecmaVMInterface);
96 
97     auto heap = vm->GetHeap();
98     heap->GetConcurrentMarker()->Mark();
99     SharedHeap::GetInstance()->TriggerUnifiedGCMark<TriggerGCType::UNIFIED_GC, GCReason::CROSSREF_CAUSE>(thread);
100     while (!thread->HasSuspendRequest()) {}
101     thread->WaitSuspension();
102 }
103 
HWTEST_F_L0(UnifiedGCTest,TriggerUnifiedGCMarkTest3)104 HWTEST_F_L0(UnifiedGCTest, TriggerUnifiedGCMarkTest3)
105 {
106     EcmaVM *vm = thread->GetEcmaVM();
107     auto stsVMInterface = std::make_unique<STSVMInterfaceTest>();
108     void *ecmaVMInterface = nullptr;
109     CrossVMOperator::DoHandshake(vm, stsVMInterface.get(), &ecmaVMInterface);
110 
111     SharedHeap::GetInstance()->TriggerUnifiedGCMark<TriggerGCType::UNIFIED_GC, GCReason::CROSSREF_CAUSE>(thread);
112     while (!thread->HasSuspendRequest()) {}
113     thread->WaitSuspension();
114     vm->CollectGarbage(TriggerGCType::YOUNG_GC);
115 }
116 
IsObjectMarked(TaggedObject * object)117 static inline bool IsObjectMarked(TaggedObject *object)
118 {
119     Region *objectRegion = Region::ObjectAddressToRange(object);
120     return objectRegion->Test(object);
121 }
122 
HWTEST_F_L0(UnifiedGCTest,IsObjectAliveTest)123 HWTEST_F_L0(UnifiedGCTest, IsObjectAliveTest)
124 {
125     EcmaVM *vm = thread->GetEcmaVM();
126     vm->SetEnableForceGC(false);
127 
128     JSHandle<JSTaggedValue> arrayInXRefRoot = JSArray::ArrayCreate(thread, JSTaggedNumber(INT_VALUE_1));
129     JSHandle<JSTaggedValue> arrayRefByXRefRoot = JSArray::ArrayCreate(thread, JSTaggedNumber(INT_VALUE_2));
130     thread->NewXRefGlobalHandle(arrayInXRefRoot.GetTaggedType());
131     JSArray::FastSetPropertyByValue(thread, arrayInXRefRoot, INT_VALUE_0, arrayRefByXRefRoot);
132 
133     auto oldArray = vm->GetFactory()->NewFromASCII("123");
134     EXPECT_TRUE(!panda::JSNApi::IsObjectAlive(vm, reinterpret_cast<uintptr_t>(&oldArray)));
135 }
136 
HWTEST_F_L0(UnifiedGCTest,IsValidHeapObjectTest)137 HWTEST_F_L0(UnifiedGCTest, IsValidHeapObjectTest)
138 {
139     EcmaVM *vm = thread->GetEcmaVM();
140     vm->SetEnableForceGC(false);
141 
142     JSHandle<JSTaggedValue> arrayInXRefRoot = JSArray::ArrayCreate(thread, JSTaggedNumber(INT_VALUE_1));
143     JSHandle<JSTaggedValue> arrayRefByXRefRoot = JSArray::ArrayCreate(thread, JSTaggedNumber(INT_VALUE_2));
144     thread->NewXRefGlobalHandle(arrayInXRefRoot.GetTaggedType());
145     JSArray::FastSetPropertyByValue(thread, arrayInXRefRoot, INT_VALUE_0, arrayRefByXRefRoot);
146 
147     auto oldArray = vm->GetFactory()->NewFromASCII("123");
148     EXPECT_TRUE(!panda::JSNApi::IsValidHeapObject(vm, reinterpret_cast<uintptr_t>(&oldArray)));
149 }
150 
HWTEST_F_L0(UnifiedGCTest,MarkFromObjectTest)151 HWTEST_F_L0(UnifiedGCTest, MarkFromObjectTest)
152 {
153     EcmaVM *vm = thread->GetEcmaVM();
154     vm->SetEnableForceGC(false);
155 
156     JSHandle<JSTaggedValue> arrayInXRefRoot = JSArray::ArrayCreate(thread, JSTaggedNumber(INT_VALUE_1));
157     JSHandle<JSTaggedValue> arrayRefByXRefRoot = JSArray::ArrayCreate(thread, JSTaggedNumber(INT_VALUE_2));
158     thread->NewXRefGlobalHandle(arrayInXRefRoot.GetTaggedType());
159     JSArray::FastSetPropertyByValue(thread, arrayInXRefRoot, INT_VALUE_0, arrayRefByXRefRoot);
160 
161     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
162     vm->GetCrossVMOperator()->MarkFromObject(arrayInXRefRoot->GetRawData());
163     heap->WaitRunningTaskFinished();
164     EXPECT_TRUE(IsObjectMarked(arrayInXRefRoot->GetHeapObject()));
165     EXPECT_TRUE(IsObjectMarked(arrayRefByXRefRoot->GetHeapObject()));
166 
167     // Clear mark bit
168     heap->Resume(TriggerGCType::UNIFIED_GC);
169     heap->WaitClearTaskFinished();
170     EXPECT_TRUE(!IsObjectMarked(arrayInXRefRoot->GetHeapObject()));
171     EXPECT_TRUE(!IsObjectMarked(arrayRefByXRefRoot->GetHeapObject()));
172     vm->SetEnableForceGC(true);
173 }
174 
HWTEST_F_L0(UnifiedGCTest,TriggerUnifiedGCFailTest)175 HWTEST_F_L0(UnifiedGCTest, TriggerUnifiedGCFailTest)
176 {
177     EcmaVM *vm = thread->GetEcmaVM();
178     auto stsVMInterface = std::make_unique<STSVMInterfaceTest>();
179     void *ecmaVMInterface = nullptr;
180     CrossVMOperator::DoHandshake(vm, stsVMInterface.get(), &ecmaVMInterface);
181 
182     CrossReferenceObjectBuilder CrossReferenceObject(vm, thread);
183     SharedHeap::GetInstance()->TriggerUnifiedGCMark<TriggerGCType::UNIFIED_GC, GCReason::CROSSREF_CAUSE>(thread);
184     vm->GetCrossVMOperator()->GetEcmaVMInterface()->NotifyXGCInterruption();
185     while (!thread->HasSuspendRequest()) {}
186     thread->WaitSuspension();
187     CrossReferenceObject.CheckResultAfterUnifiedGCTriggerFail();
188 }
189 
HWTEST_F_L0(UnifiedGCVerificationTest,VerifyUnifiedGCMarkTest)190 HWTEST_F_L0(UnifiedGCVerificationTest, VerifyUnifiedGCMarkTest)
191 {
192     EcmaVM *vm = thread->GetEcmaVM();
193     vm->SetEnableForceGC(false);
194     auto stsVMInterface = std::make_unique<STSVMInterfaceTest>();
195     void *ecmaVMInterface = nullptr;
196     CrossVMOperator::DoHandshake(vm, stsVMInterface.get(), &ecmaVMInterface);
197     SharedHeap::GetInstance()->TriggerUnifiedGCMark<TriggerGCType::UNIFIED_GC, GCReason::CROSSREF_CAUSE>(thread);
198     while (!thread->HasSuspendRequest()) {}
199     thread->WaitSuspension();
200     vm->SetEnableForceGC(true);
201 }
202 #endif  // PANDA_JS_ETS_HYBRID_MODE
203 }  // namespace panda::test