• 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 "common_interfaces/objects/base_string_table.h"
17 
18 #include "common_components/base/globals.h"
19 #include "common_interfaces/objects/composite_base_class.h"
20 #include "common_components/objects/string_table/hashtriemap.h"
21 #include "common_components/objects/string_table/hashtriemap-inl.h"
22 #include "common_components/objects/string_table_internal.h"
23 #include "common_components/taskpool/taskpool.h"
24 #include "common_components/mutator/thread_local.h"
25 #include "common_interfaces/objects/base_string.h"
26 #include "common_interfaces/thread/thread_holder.h"
27 #include "common_interfaces/thread/thread_state_transition.h"
28 #include "heap/heap_allocator.h"
29 
30 namespace common {
31 template <bool ConcurrentSweep>
AllocateLineStringObject(size_t size)32 BaseString* BaseStringTableInternal<ConcurrentSweep>::AllocateLineStringObject(size_t size)
33 {
34     size = AlignUp(size, ALIGN_OBJECT);
35     BaseString* str =
36         reinterpret_cast<BaseString*>(HeapAllocator::AllocateInOldOrHuge(size, LanguageType::DYNAMIC));
37     BaseClass* cls = BaseRuntime::GetInstance()->GetBaseClassRoots().GetBaseClass(CommonType::LINE_STRING);
38     str->SetFullBaseClassWithoutBarrier(cls);
39     return str;
40 }
41 
42 template <bool ConcurrentSweep>
GetOrInternFlattenString(ThreadHolder * holder,const HandleCreator & handleCreator,BaseString * string)43 BaseString* BaseStringTableInternal<ConcurrentSweep>::GetOrInternFlattenString(
44     ThreadHolder* holder, const HandleCreator& handleCreator,
45     BaseString* string)
46 {
47     ASSERT(string->NotTreeString());
48     if (string->IsInternString()) {
49         return string;
50     }
51     auto readBarrier = [](void* obj, size_t offset)-> BaseObject* {
52         return BaseObject::Cast(
53             reinterpret_cast<MAddress>(BaseRuntime::ReadBarrier(
54                 obj, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(obj) + offset))));
55     };
56     uint32_t hashcode = string->GetHashcode(readBarrier);
57     // Strings in string table should not be in the young space.
58     auto loadResult = stringTable_.template Load(readBarrier, hashcode, string);
59     if (loadResult.value != nullptr) {
60         return loadResult.value;
61     }
62     ReadOnlyHandle<BaseString> stringHandle = handleCreator(holder, string);
63     BaseString* result = stringTable_.template StoreOrLoad(
64         holder, readBarrier, hashcode, loadResult, stringHandle);
65     ASSERT(result != nullptr);
66     return result;
67 }
68 
69 template <bool ConcurrentSweep>
GetOrInternStringFromCompressedSubString(ThreadHolder * holder,const HandleCreator & handleCreator,const ReadOnlyHandle<BaseString> & string,uint32_t offset,uint32_t utf8Len)70 BaseString* BaseStringTableInternal<ConcurrentSweep>::GetOrInternStringFromCompressedSubString(ThreadHolder* holder,
71     const HandleCreator& handleCreator,
72     const ReadOnlyHandle<BaseString>& string,
73     uint32_t offset, uint32_t utf8Len)
74 {
75     const uint8_t* utf8Data = string->GetDataUtf8() + offset;
76     uint32_t hashcode = BaseString::ComputeHashcodeUtf8(utf8Data, utf8Len, true);
77     auto readBarrier = [](void* obj, size_t offset)-> BaseObject* {
78         return BaseObject::Cast(
79             reinterpret_cast<MAddress>(BaseRuntime::ReadBarrier(
80                 obj, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(obj) + offset))));
81     };
82     auto loadResult = stringTable_.template Load(readBarrier, hashcode, string, offset, utf8Len);
83     if (loadResult.value != nullptr) {
84         return loadResult.value;
85     }
86     auto allocator = [](size_t size, CommonType type)-> BaseString* {
87         ASSERT(type == CommonType::LINE_STRING);
88         return AllocateLineStringObject(size);
89     };
90     BaseString* result = stringTable_.template StoreOrLoad(
91         holder, hashcode, loadResult,
92         [holder, string, offset, utf8Len, hashcode, handleCreator, allocator]() {
93             BaseString* str = BaseString::CreateFromUtf8CompressedSubString(
94                 std::move(allocator), string, offset, utf8Len);
95             str->SetMixHashcode(hashcode);
96             ASSERT(!str->IsInternString());
97             ASSERT(str->NotTreeString());
98             // Strings in string table should not be in the young space.
99             ReadOnlyHandle<BaseString> strHandle = handleCreator(holder, str);
100             return strHandle;
101         },
102         [utf8Len, string, offset](const BaseString* foundString) {
103             const uint8_t* utf8Data = string->GetDataUtf8() + offset;
104             auto readBarrier = [](void* obj, size_t offset)-> BaseObject* {
105                 return BaseObject::Cast(
106                     reinterpret_cast<MAddress>(BaseRuntime::ReadBarrier(
107                         obj, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(obj) + offset))));
108             };
109             return BaseString::StringIsEqualUint8Data(readBarrier, foundString, utf8Data, utf8Len, true);
110         });
111     ASSERT(result != nullptr);
112     return result;
113 }
114 
115 template <bool ConcurrentSweep>
GetOrInternString(ThreadHolder * holder,const HandleCreator & handleCreator,const uint8_t * utf8Data,uint32_t utf8Len,bool canBeCompress)116 BaseString* BaseStringTableInternal<ConcurrentSweep>::GetOrInternString(ThreadHolder* holder,
117                                                                         const HandleCreator& handleCreator,
118                                                                         const uint8_t* utf8Data,
119                                                                         uint32_t utf8Len,
120                                                                         bool canBeCompress)
121 {
122     uint32_t hashcode = BaseString::ComputeHashcodeUtf8(utf8Data, utf8Len, canBeCompress);
123     auto allocator = [](size_t size, CommonType type)-> BaseString* {
124         ASSERT(type == CommonType::LINE_STRING);
125         return AllocateLineStringObject(size);
126     };
127     BaseString* result = stringTable_.template LoadOrStore<true>(
128         holder, hashcode,
129         [holder, hashcode, utf8Data, utf8Len, canBeCompress, handleCreator, allocator]() {
130             BaseString* value = BaseString::CreateFromUtf8(std::move(allocator), utf8Data, utf8Len, canBeCompress);
131             value->SetMixHashcode(hashcode);
132             ASSERT(!value->IsInternString());
133             ASSERT(value->NotTreeString());
134             ReadOnlyHandle<BaseString> stringHandle = handleCreator(holder, value);
135             return stringHandle;
136         },
137         [utf8Data, utf8Len, canBeCompress](BaseString* foundString) {
138             auto readBarrier = [](void* obj, size_t offset)-> BaseObject* {
139                 return BaseObject::Cast(
140                     reinterpret_cast<MAddress>(BaseRuntime::ReadBarrier(
141                         obj, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(obj) + offset))));
142             };
143             return BaseString::StringIsEqualUint8Data(readBarrier, foundString, utf8Data, utf8Len,
144                                                       canBeCompress);
145         });
146     ASSERT(result != nullptr);
147     return result;
148 }
149 
150 template <bool ConcurrentSweep>
GetOrInternString(ThreadHolder * holder,const HandleCreator & handleCreator,const uint16_t * utf16Data,uint32_t utf16Len,bool canBeCompress)151 BaseString* BaseStringTableInternal<ConcurrentSweep>::GetOrInternString(
152     ThreadHolder* holder, const HandleCreator& handleCreator,
153     const uint16_t* utf16Data, uint32_t utf16Len,
154     bool canBeCompress)
155 {
156     uint32_t hashcode = BaseString::ComputeHashcodeUtf16(const_cast<uint16_t*>(utf16Data), utf16Len);
157     auto allocator = [](size_t size, CommonType type)-> BaseString* {
158         ASSERT(type == CommonType::LINE_STRING);
159         return AllocateLineStringObject(size);
160     };
161     BaseString* result = stringTable_.template LoadOrStore<true>(
162         holder, hashcode,
163         [holder, utf16Data, utf16Len, canBeCompress, hashcode, handleCreator, allocator]() {
164             BaseString* value = BaseString::CreateFromUtf16(std::move(allocator), utf16Data, utf16Len,
165                                                             canBeCompress);
166             value->SetMixHashcode(hashcode);
167             ASSERT(!value->IsInternString());
168             ASSERT(value->NotTreeString());
169             // Strings in string table should not be in the young space.
170             ReadOnlyHandle<BaseString> stringHandle = handleCreator(holder, value);
171             return stringHandle;
172         },
173         [utf16Data, utf16Len](BaseString* foundString) {
174             auto readBarrier = [](void* obj, size_t offset)-> BaseObject* {
175                 return BaseObject::Cast(
176                     reinterpret_cast<MAddress>(BaseRuntime::ReadBarrier(
177                         obj, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(obj) + offset))));
178             };
179             return BaseString::StringsAreEqualUtf16(readBarrier, foundString, utf16Data, utf16Len);
180         });
181     ASSERT(result != nullptr);
182     return result;
183 }
184 
185 template <bool ConcurrentSweep>
TryGetInternString(const ReadOnlyHandle<BaseString> & string)186 BaseString* BaseStringTableInternal<ConcurrentSweep>::TryGetInternString(const ReadOnlyHandle<BaseString>& string)
187 {
188     auto readBarrier = [](void* obj, size_t offset)-> BaseObject* {
189         return BaseObject::Cast(
190             reinterpret_cast<MAddress>(BaseRuntime::ReadBarrier(
191                 obj, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(obj) + offset))));
192     };
193     uint32_t hashcode = string->GetHashcode(readBarrier);
194     return stringTable_.template Load<false>(readBarrier, hashcode, *string);
195 }
196 
197 template <bool ConcurrentSweep>
198 template <bool B, std::enable_if_t<B, int>>
SweepWeakRef(const WeakRefFieldVisitor & visitor,uint32_t rootID,std::vector<HashTrieMapEntry * > & waitDeleteEntries)199 void BaseStringTableInternal<ConcurrentSweep>::SweepWeakRef(const WeakRefFieldVisitor& visitor, uint32_t rootID,
200                                                             std::vector<HashTrieMapEntry*>& waitDeleteEntries)
201 {
202     ASSERT(rootID >= 0 && rootID < TrieMapConfig::ROOT_SIZE);
203     auto rootNode = stringTable_.root_[rootID].load(std::memory_order_relaxed);
204     if (rootNode == nullptr) {
205         return;
206     }
207     for (uint32_t index = 0; index < TrieMapConfig::INDIRECT_SIZE; ++index) {
208         stringTable_.ClearNodeFromGC(rootNode, index, visitor, waitDeleteEntries);
209     }
210 }
211 
212 template <bool ConcurrentSweep>
213 template <bool B, std::enable_if_t<B, int>>
CleanUp()214 void BaseStringTableInternal<ConcurrentSweep>::CleanUp()
215 {
216     stringTable_.CleanUp();
217 }
218 
219 template <bool ConcurrentSweep>
220 template <bool B, std::enable_if_t<!B, int>>
SweepWeakRef(const WeakRefFieldVisitor & visitor)221 void BaseStringTableInternal<ConcurrentSweep>::SweepWeakRef(const WeakRefFieldVisitor& visitor)
222 {
223     // No need lock here, only shared gc will sweep string table, meanwhile other threads are suspended.
224     for (uint32_t rootID = 0; rootID < TrieMapConfig::ROOT_SIZE; ++rootID) {
225         auto rootNode = stringTable_.root_[rootID].load(std::memory_order_relaxed);
226         if (rootNode == nullptr) {
227             continue;
228         }
229         for (uint32_t index = 0; index < TrieMapConfig::INDIRECT_SIZE; ++index) {
230             stringTable_.ClearNodeFromGC(rootNode, index, visitor);
231         }
232     }
233 }
234 
235 template void BaseStringTableInternal<false>::SweepWeakRef<false>(const WeakRefFieldVisitor& visitor);
236 
GetOrInternFlattenString(ThreadHolder * holder,const HandleCreator & handleCreator,BaseString * string)237 BaseString* BaseStringTableImpl::GetOrInternFlattenString(ThreadHolder* holder, const HandleCreator& handleCreator,
238                                                           BaseString* string)
239 {
240     return stringTable_.GetOrInternFlattenString(holder, handleCreator, string);
241 }
242 
GetOrInternStringFromCompressedSubString(ThreadHolder * holder,const HandleCreator & handleCreator,const ReadOnlyHandle<BaseString> & string,uint32_t offset,uint32_t utf8Len)243 BaseString* BaseStringTableImpl::GetOrInternStringFromCompressedSubString(
244     ThreadHolder* holder, const HandleCreator& handleCreator,
245     const ReadOnlyHandle<BaseString>& string, uint32_t offset, uint32_t utf8Len)
246 {
247     return stringTable_.GetOrInternStringFromCompressedSubString(holder, handleCreator, string, offset, utf8Len);
248 }
249 
GetOrInternString(ThreadHolder * holder,const HandleCreator & handleCreator,const uint8_t * utf8Data,uint32_t utf8Len,bool canBeCompress)250 BaseString* BaseStringTableImpl::GetOrInternString(ThreadHolder* holder, const HandleCreator& handleCreator,
251                                                    const uint8_t* utf8Data, uint32_t utf8Len, bool canBeCompress)
252 {
253     return stringTable_.GetOrInternString(holder, handleCreator, utf8Data, utf8Len, canBeCompress);
254 }
255 
GetOrInternString(ThreadHolder * holder,const HandleCreator & handleCreator,const uint16_t * utf16Data,uint32_t utf16Len,bool canBeCompress)256 BaseString* BaseStringTableImpl::GetOrInternString(ThreadHolder* holder, const HandleCreator& handleCreator,
257                                                    const uint16_t* utf16Data, uint32_t utf16Len, bool canBeCompress)
258 {
259     return stringTable_.GetOrInternString(holder, handleCreator, utf16Data, utf16Len, canBeCompress);
260 }
261 
TryGetInternString(const ReadOnlyHandle<BaseString> & string)262 BaseString* BaseStringTableImpl::TryGetInternString(const ReadOnlyHandle<BaseString>& string)
263 {
264     return stringTable_.TryGetInternString(string);
265 }
266 
StartSweepWeakRefTask()267 void BaseStringTableCleaner::StartSweepWeakRefTask()
268 {
269     // No need lock here, only the daemon thread will reset the state.
270     sweepWeakRefFinished_ = false;
271     PendingTaskCount_.store(TrieMapConfig::ROOT_SIZE, std::memory_order_relaxed);
272 }
273 
WaitSweepWeakRefTask()274 void BaseStringTableCleaner::WaitSweepWeakRefTask()
275 {
276     LockHolder holder(sweepWeakRefMutex_);
277     while (!sweepWeakRefFinished_) {
278         sweepWeakRefCV_.Wait(&sweepWeakRefMutex_);
279     }
280 }
281 
SignalSweepWeakRefTask()282 void BaseStringTableCleaner::SignalSweepWeakRefTask()
283 {
284     LockHolder holder(sweepWeakRefMutex_);
285     sweepWeakRefFinished_ = true;
286     sweepWeakRefCV_.SignalAll();
287 }
288 
289 
PostSweepWeakRefTask(const WeakRefFieldVisitor & visitor)290 void BaseStringTableCleaner::PostSweepWeakRefTask(const WeakRefFieldVisitor &visitor)
291 {
292     StartSweepWeakRefTask();
293     stringTable_->GetHashTrieMap().StartSweeping();
294     iter_ = std::make_shared<std::atomic<uint32_t>>(0U);
295     const uint32_t postTaskCount =
296         Taskpool::GetCurrentTaskpool()->GetTotalThreadNum();
297     for (uint32_t i = 0U; i < postTaskCount; ++i) {
298         Taskpool::GetCurrentTaskpool()->PostTask(
299             std::make_unique<CMCSweepWeakRefTask>(iter_, this, visitor));
300     }
301 }
302 
JoinAndWaitSweepWeakRefTask(const WeakRefFieldVisitor & visitor)303 void BaseStringTableCleaner::JoinAndWaitSweepWeakRefTask(
304     const WeakRefFieldVisitor &visitor)
305 {
306     ProcessSweepWeakRef(iter_, this, visitor);
307     WaitSweepWeakRefTask();
308     iter_.reset();
309     stringTable_->GetHashTrieMap().FinishSweeping();
310 }
311 
CleanUp()312 void BaseStringTableCleaner::CleanUp()
313 {
314     for (std::vector<HashTrieMapEntry*>& waitFrees : waitFreeEntries_) {
315         for (const HashTrieMapEntry* entry : waitFrees) {
316             delete entry;
317         }
318         waitFrees.clear();
319     }
320     stringTable_->CleanUp();
321 }
322 
ProcessSweepWeakRef(IteratorPtr & iter,BaseStringTableCleaner * cleaner,const WeakRefFieldVisitor & visitor)323 void BaseStringTableCleaner::ProcessSweepWeakRef(
324     IteratorPtr &iter, BaseStringTableCleaner *cleaner,
325     const WeakRefFieldVisitor &visitor)
326 {
327     uint32_t index = 0U;
328     while ((index = GetNextIndexId(iter)) < TrieMapConfig::ROOT_SIZE) {
329         cleaner->waitFreeEntries_[index].clear();
330         cleaner->stringTable_->SweepWeakRef(visitor, index, cleaner->waitFreeEntries_[index]);
331         if (ReduceCountAndCheckFinish(cleaner)) {
332             cleaner->SignalSweepWeakRefTask();
333         }
334     }
335 }
336 
Run(uint32_t threadIndex)337 bool BaseStringTableCleaner::CMCSweepWeakRefTask::Run([[maybe_unused]] uint32_t threadIndex)
338 {
339     ThreadLocal::SetThreadType(ThreadType::GC_THREAD);
340     ProcessSweepWeakRef(iter_, cleaner_, visitor_);
341     ThreadLocal::SetThreadType(ThreadType::ARK_PROCESSOR);
342     ThreadLocal::ClearAllocBufferRegion();
343     return true;
344 }
345 }
346