• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "runtime/string_table.h"
17 
18 #include "runtime/include/runtime.h"
19 #include "runtime/mem/object_helpers.h"
20 
21 namespace panda {
22 
GetOrInternString(const uint8_t * mutf8_data,uint32_t utf16_length,LanguageContext ctx)23 coretypes::String *StringTable::GetOrInternString(const uint8_t *mutf8_data, uint32_t utf16_length, LanguageContext ctx)
24 {
25     bool can_be_compressed = coretypes::String::CanBeCompressedMUtf8(mutf8_data);
26     auto *str = internal_table_.GetString(mutf8_data, utf16_length, can_be_compressed, ctx);
27     if (str == nullptr) {
28         str = table_.GetOrInternString(mutf8_data, utf16_length, can_be_compressed, ctx);
29     }
30     return str;
31 }
32 
GetOrInternString(const uint16_t * utf16_data,uint32_t utf16_length,LanguageContext ctx)33 coretypes::String *StringTable::GetOrInternString(const uint16_t *utf16_data, uint32_t utf16_length,
34                                                   LanguageContext ctx)
35 {
36     auto *str = internal_table_.GetString(utf16_data, utf16_length, ctx);
37     if (str == nullptr) {
38         str = table_.GetOrInternString(utf16_data, utf16_length, ctx);
39     }
40     return str;
41 }
42 
GetOrInternString(coretypes::String * string,LanguageContext ctx)43 coretypes::String *StringTable::GetOrInternString(coretypes::String *string, LanguageContext ctx)
44 {
45     auto *str = internal_table_.GetString(string, ctx);
46     if (str == nullptr) {
47         str = table_.GetOrInternString(string, ctx);
48     }
49     return str;
50 }
51 
GetOrInternInternalString(const panda_file::File & pf,panda_file::File::EntityId id,LanguageContext ctx)52 coretypes::String *StringTable::GetOrInternInternalString(const panda_file::File &pf, panda_file::File::EntityId id,
53                                                           LanguageContext ctx)
54 {
55     auto data = pf.GetStringData(id);
56     coretypes::String *str = table_.GetString(data.data, data.utf16_length, data.is_ascii, ctx);
57     if (str != nullptr) {
58         return str;
59     }
60     return internal_table_.GetOrInternString(pf, id, ctx);
61 }
62 
Sweep(const GCObjectVisitor & gc_object_visitor)63 void StringTable::Sweep(const GCObjectVisitor &gc_object_visitor)
64 {
65     table_.Sweep(gc_object_visitor);
66 }
67 
UpdateMoved()68 bool StringTable::UpdateMoved()
69 {
70     return table_.UpdateMoved();
71 }
72 
Size()73 size_t StringTable::Size()
74 {
75     return internal_table_.Size() + table_.Size();
76 }
77 
GetString(const uint8_t * utf8_data,uint32_t utf16_length,bool can_be_compressed,LanguageContext ctx)78 coretypes::String *StringTable::Table::GetString(const uint8_t *utf8_data, uint32_t utf16_length,
79                                                  bool can_be_compressed, [[maybe_unused]] LanguageContext ctx)
80 {
81     uint32_t hash_code = coretypes::String::ComputeHashcodeMutf8(utf8_data, utf16_length, can_be_compressed);
82     os::memory::ReadLockHolder holder(table_lock_);
83     for (auto it = table_.find(hash_code); it != table_.end(); it++) {
84         auto found_string = it->second;
85         if (coretypes::String::StringsAreEqualMUtf8(found_string, utf8_data, utf16_length, can_be_compressed)) {
86             return found_string;
87         }
88     }
89     return nullptr;
90 }
91 
GetString(const uint16_t * utf16_data,uint32_t utf16_length,LanguageContext ctx)92 coretypes::String *StringTable::Table::GetString(const uint16_t *utf16_data, uint32_t utf16_length,
93                                                  [[maybe_unused]] LanguageContext ctx)
94 {
95     uint32_t hash_code = coretypes::String::ComputeHashcodeUtf16(const_cast<uint16_t *>(utf16_data), utf16_length);
96     os::memory::ReadLockHolder holder(table_lock_);
97     for (auto it = table_.find(hash_code); it != table_.end(); it++) {
98         auto found_string = it->second;
99         if (coretypes::String::StringsAreEqualUtf16(found_string, utf16_data, utf16_length)) {
100             return found_string;
101         }
102     }
103     return nullptr;
104 }
105 
GetString(coretypes::String * string,LanguageContext ctx)106 coretypes::String *StringTable::Table::GetString([[maybe_unused]] coretypes::String *string,
107                                                  [[maybe_unused]] LanguageContext ctx)
108 {
109     os::memory::ReadLockHolder holder(table_lock_);
110     auto hash = string->GetHashcode();
111     for (auto it = table_.find(hash); it != table_.end(); it++) {
112         auto found_string = it->second;
113         if (coretypes::String::StringsAreEqual(found_string, string)) {
114             return found_string;
115         }
116     }
117     return nullptr;
118 }
119 
ForceInternString(coretypes::String * string,LanguageContext ctx)120 void StringTable::Table::ForceInternString(coretypes::String *string, [[maybe_unused]] LanguageContext ctx)
121 {
122     os::memory::WriteLockHolder holder(table_lock_);
123     table_.insert(std::pair<uint32_t, coretypes::String *>(string->GetHashcode(), string));
124 }
125 
InternString(coretypes::String * string,LanguageContext ctx)126 coretypes::String *StringTable::Table::InternString(coretypes::String *string, [[maybe_unused]] LanguageContext ctx)
127 {
128     uint32_t hash_code = string->GetHashcode();
129     os::memory::WriteLockHolder holder(table_lock_);
130     // Check string is not present before actually creating and inserting
131     for (auto it = table_.find(hash_code); it != table_.end(); it++) {
132         auto found_string = it->second;
133         if (coretypes::String::StringsAreEqual(found_string, string)) {
134             return found_string;
135         }
136     }
137     table_.insert(std::pair<uint32_t, coretypes::String *>(hash_code, string));
138     return string;
139 }
140 
GetOrInternString(const uint8_t * mutf8_data,uint32_t utf16_length,bool can_be_compressed,LanguageContext ctx)141 coretypes::String *StringTable::Table::GetOrInternString(const uint8_t *mutf8_data, uint32_t utf16_length,
142                                                          bool can_be_compressed, LanguageContext ctx)
143 {
144     coretypes::String *result = GetString(mutf8_data, utf16_length, can_be_compressed, ctx);
145     if (result != nullptr) {
146         return result;
147     }
148 
149     // Even if this string is not inserted, it should get removed during GC
150     result = coretypes::String::CreateFromMUtf8(mutf8_data, utf16_length, can_be_compressed, ctx,
151                                                 Runtime::GetCurrent()->GetPandaVM());
152 
153     result = InternString(result, ctx);
154 
155     return result;
156 }
157 
GetOrInternString(const uint16_t * utf16_data,uint32_t utf16_length,LanguageContext ctx)158 coretypes::String *StringTable::Table::GetOrInternString(const uint16_t *utf16_data, uint32_t utf16_length,
159                                                          LanguageContext ctx)
160 {
161     coretypes::String *result = GetString(utf16_data, utf16_length, ctx);
162     if (result != nullptr) {
163         return result;
164     }
165 
166     // Even if this string is not inserted, it should get removed during GC
167     result = coretypes::String::CreateFromUtf16(utf16_data, utf16_length, ctx, Runtime::GetCurrent()->GetPandaVM());
168 
169     result = InternString(result, ctx);
170 
171     return result;
172 }
173 
GetOrInternString(coretypes::String * string,LanguageContext ctx)174 coretypes::String *StringTable::Table::GetOrInternString(coretypes::String *string, LanguageContext ctx)
175 {
176     coretypes::String *result = GetString(string, ctx);
177     if (result != nullptr) {
178         return result;
179     }
180     result = InternString(string, ctx);
181     return result;
182 }
183 
UpdateMoved()184 bool StringTable::Table::UpdateMoved()
185 {
186     os::memory::WriteLockHolder holder(table_lock_);
187     LOG(DEBUG, GC) << "=== StringTable Update moved. BEGIN ===";
188     LOG(DEBUG, GC) << "Iterate over: " << table_.size() << " elements in string table";
189     bool updated = false;
190     for (auto it = table_.begin(), end = table_.end(); it != end;) {
191         auto *object = it->second;
192         if (object->IsForwarded()) {
193             ObjectHeader *fwd_string = panda::mem::GetForwardAddress(object);
194             it->second = static_cast<coretypes::String *>(fwd_string);
195             LOG(DEBUG, GC) << "StringTable: forward " << std::hex << object << " -> " << fwd_string;
196             updated = true;
197         }
198         ++it;
199     }
200     LOG(DEBUG, GC) << "=== StringTable Update moved. END ===";
201     return updated;
202 }
203 
Sweep(const GCObjectVisitor & gc_object_visitor)204 void StringTable::Table::Sweep(const GCObjectVisitor &gc_object_visitor)
205 {
206     os::memory::WriteLockHolder holder(table_lock_);
207     LOG(DEBUG, GC) << "=== StringTable Sweep. BEGIN ===";
208     LOG(DEBUG, GC) << "StringTable iterate over: " << table_.size() << " elements in string table";
209     for (auto it = table_.begin(), end = table_.end(); it != end;) {
210         auto *object = it->second;
211         if (object->IsForwarded()) {
212             ASSERT(gc_object_visitor(object) != ObjectStatus::DEAD_OBJECT);
213             ObjectHeader *fwd_string = panda::mem::GetForwardAddress(object);
214             it->second = static_cast<coretypes::String *>(fwd_string);
215             ++it;
216             LOG(DEBUG, GC) << "StringTable: forward " << std::hex << object << " -> " << fwd_string;
217         } else if (gc_object_visitor(object) == ObjectStatus::DEAD_OBJECT) {
218             LOG(DEBUG, GC) << "StringTable: delete string " << std::hex << object
219                            << ", val = " << ConvertToString(object);
220             table_.erase(it++);
221         } else {
222             ++it;
223         }
224     }
225     LOG(DEBUG, GC) << "StringTable size after sweep = " << table_.size();
226     LOG(DEBUG, GC) << "=== StringTable Sweep. END ===";
227 }
228 
Size()229 size_t StringTable::Table::Size()
230 {
231     os::memory::ReadLockHolder holder(table_lock_);
232     return table_.size();
233 }
234 
GetOrInternString(const uint8_t * mutf8_data,uint32_t utf16_length,bool can_be_compressed,LanguageContext ctx)235 coretypes::String *StringTable::InternalTable::GetOrInternString(const uint8_t *mutf8_data, uint32_t utf16_length,
236                                                                  bool can_be_compressed, LanguageContext ctx)
237 {
238     coretypes::String *result = GetString(mutf8_data, utf16_length, can_be_compressed, ctx);
239     if (result != nullptr) {
240         return result;
241     }
242 
243     result = coretypes::String::CreateFromMUtf8(mutf8_data, utf16_length, can_be_compressed, ctx,
244                                                 Runtime::GetCurrent()->GetPandaVM(), false);
245     return InternStringNonMovable(result, ctx);
246 }
247 
GetOrInternString(const uint16_t * utf16_data,uint32_t utf16_length,LanguageContext ctx)248 coretypes::String *StringTable::InternalTable::GetOrInternString(const uint16_t *utf16_data, uint32_t utf16_length,
249                                                                  LanguageContext ctx)
250 {
251     coretypes::String *result = GetString(utf16_data, utf16_length, ctx);
252     if (result != nullptr) {
253         return result;
254     }
255 
256     result =
257         coretypes::String::CreateFromUtf16(utf16_data, utf16_length, ctx, Runtime::GetCurrent()->GetPandaVM(), false);
258     return InternStringNonMovable(result, ctx);
259 }
260 
GetOrInternString(const panda_file::File & pf,panda_file::File::EntityId id,LanguageContext ctx)261 coretypes::String *StringTable::InternalTable::GetOrInternString(const panda_file::File &pf,
262                                                                  panda_file::File::EntityId id, LanguageContext ctx)
263 {
264     auto data = pf.GetStringData(id);
265     coretypes::String *result = GetString(data.data, data.utf16_length, data.is_ascii, ctx);
266     if (result != nullptr) {
267         return result;
268     }
269     result = coretypes::String::CreateFromMUtf8(data.data, data.utf16_length, data.is_ascii, ctx,
270                                                 Runtime::GetCurrent()->GetPandaVM(), false);
271     result = InternStringNonMovable(result, ctx);
272 
273     // Update cache.
274     os::memory::WriteLockHolder lock(maps_lock_);
275     auto it = maps_.find(&pf);
276     if (it != maps_.end()) {
277         (it->second)[id] = result;
278     } else {
279         PandaUnorderedMap<panda_file::File::EntityId, coretypes::String *, EntityIdEqual> map;
280         map[id] = result;
281         maps_[&pf] = std::move(map);
282     }
283     return result;
284 }
285 
GetStringFast(const panda_file::File & pf,panda_file::File::EntityId id)286 coretypes::String *StringTable::InternalTable::GetStringFast(const panda_file::File &pf, panda_file::File::EntityId id)
287 {
288     os::memory::ReadLockHolder lock(maps_lock_);
289     auto it = maps_.find(&pf);
290     if (it != maps_.end()) {
291         auto id_it = it->second.find(id);
292         if (id_it != it->second.end()) {
293             return id_it->second;
294         }
295     }
296     return nullptr;
297 }
298 
VisitRoots(const StringVisitor & visitor,mem::VisitGCRootFlags flags)299 void StringTable::InternalTable::VisitRoots(const StringVisitor &visitor, mem::VisitGCRootFlags flags)
300 {
301     ASSERT(BitCount(flags & (mem::VisitGCRootFlags::ACCESS_ROOT_ALL | mem::VisitGCRootFlags::ACCESS_ROOT_ONLY_NEW)) ==
302            1);
303 
304     ASSERT(BitCount(flags & (mem::VisitGCRootFlags::START_RECORDING_NEW_ROOT |
305                              mem::VisitGCRootFlags::END_RECORDING_NEW_ROOT)) <= 1);
306     // need to set flags before we iterate, cause concurrent allocation should be in proper table
307     if ((flags & mem::VisitGCRootFlags::START_RECORDING_NEW_ROOT) != 0) {
308         os::memory::WriteLockHolder holder(table_lock_);
309         record_new_string_ = true;
310     } else if ((flags & mem::VisitGCRootFlags::END_RECORDING_NEW_ROOT) != 0) {
311         os::memory::WriteLockHolder holder(table_lock_);
312         record_new_string_ = false;
313     }
314 
315     if ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ALL) != 0) {
316         os::memory::ReadLockHolder lock(table_lock_);
317         for (const auto &v : table_) {
318             visitor(v.second);
319         }
320     } else if ((flags & mem::VisitGCRootFlags::ACCESS_ROOT_ONLY_NEW) != 0) {
321         os::memory::ReadLockHolder lock(table_lock_);
322         for (const auto str : new_string_table_) {
323             visitor(str);
324         }
325     } else {
326         LOG(FATAL, RUNTIME) << "Unknown VisitGCRootFlags: " << static_cast<uint32_t>(flags);
327     }
328     if ((flags & mem::VisitGCRootFlags::END_RECORDING_NEW_ROOT) != 0) {
329         os::memory::WriteLockHolder holder(table_lock_);
330         new_string_table_.clear();
331     }
332 }
333 
InternStringNonMovable(coretypes::String * string,LanguageContext ctx)334 coretypes::String *StringTable::InternalTable::InternStringNonMovable(coretypes::String *string, LanguageContext ctx)
335 {
336     auto *result = InternString(string, ctx);
337     os::memory::WriteLockHolder holder(table_lock_);
338     if (record_new_string_) {
339         new_string_table_.push_back(result);
340     }
341     return result;
342 }
343 
344 }  // namespace panda
345