• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 #ifndef STRING_TABLE_BASE_TEST_H
17 #define STRING_TABLE_BASE_TEST_H
18 
19 #include "gtest/gtest.h"
20 #include "runtime/include/coretypes/string.h"
21 #include "runtime/include/runtime.h"
22 #include "runtime/include/thread.h"
23 #include "runtime/include/gc_task.h"
24 #include "runtime/include/panda_vm.h"
25 #include "runtime/handle_base-inl.h"
26 #include "runtime/mem/refstorage/global_object_storage.h"
27 #include "runtime/include/thread_scopes.h"
28 
29 #include "libpandafile/file.h"
30 #include "libpandafile/file_item_container.h"
31 #include "libpandafile/file_writer.h"
32 
33 #include <limits>
34 
35 namespace panda::mem::test {
36 class StringTableBaseTest : public testing::Test {
37 public:
StringTableBaseTest()38     StringTableBaseTest() {}
39 
~StringTableBaseTest()40     ~StringTableBaseTest() override
41     {
42         Runtime::Destroy();
43     }
44 
45     static coretypes::String *AllocUtf8String(std::vector<uint8_t> data, bool is_movable = true)
46     {
47         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
48         return coretypes::String::CreateFromMUtf8(data.data(), utf::MUtf8ToUtf16Size(data.data()), ctx,
49                                                   Runtime::GetCurrent()->GetPandaVM(), is_movable);
50     }
51 
SetupRuntime(const std::string & gc_type)52     void SetupRuntime(const std::string &gc_type)
53     {
54         RuntimeOptions options;
55         options.SetShouldLoadBootPandaFiles(false);
56         options.SetShouldInitializeIntrinsics(false);
57         if (gc_type == "g1-gc") {
58             options.SetYoungSpaceSize(1_MB);
59             options.SetHeapSizeLimit(3_MB);
60         } else {
61             options.SetYoungSpaceSize(18_MB);
62             options.SetHeapSizeLimit(36_MB);
63         }
64 
65         options.SetGcType(gc_type);
66         options.SetCompilerEnableJit(false);
67         Runtime::Create(options);
68 
69         thread_ = panda::MTManagedThread::GetCurrent();
70     }
71 
RunStringTableTests()72     void RunStringTableTests()
73     {
74         EmptyTable();
75         InternCompressedUtf8AndString();
76         InternUncompressedUtf8AndString();
77         InternTheSameUtf16String();
78         InternManyStrings();
79         SweepObjectInTable();
80         InternTooLongString();
81     }
82 
EmptyTable()83     void EmptyTable()
84     {
85         ScopedManagedCodeThread s(thread_);
86         auto table = StringTable();
87         ASSERT_EQ(table.Size(), 0);
88     }
89 
InternCompressedUtf8AndString()90     void InternCompressedUtf8AndString()
91     {
92         ScopedManagedCodeThread s(thread_);
93         auto table = StringTable();
94         std::vector<uint8_t> data {0x01, 0x02, 0x03, 0x00};
95         auto *string = AllocUtf8String(data);
96         auto *interned_str1 =
97             table.GetOrInternString(data.data(), data.size() - 1,
98                                     Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY));
99         auto *interned_str2 = table.GetOrInternString(
100             string, Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY));
101         ASSERT_EQ(interned_str1, interned_str2);
102         ASSERT_EQ(table.Size(), 1);
103     }
104 
InternUncompressedUtf8AndString()105     void InternUncompressedUtf8AndString()
106     {
107         ScopedManagedCodeThread s(thread_);
108         auto table = StringTable();
109         std::vector<uint8_t> data {0xc2, 0xa7, 0x34, 0x00};
110         auto *string = AllocUtf8String(data);
111         auto *interned_str1 = table.GetOrInternString(
112             data.data(), 2, Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY));
113         auto *interned_str2 = table.GetOrInternString(
114             string, Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY));
115         ASSERT_EQ(interned_str1, interned_str2);
116         ASSERT_EQ(table.Size(), 1);
117     }
118 
InternTheSameUtf16String()119     void InternTheSameUtf16String()
120     {
121         ScopedManagedCodeThread s(thread_);
122         auto table = StringTable();
123         std::vector<uint16_t> data {0xffc3, 0x33, 0x00};
124 
125         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
126         auto *first_string =
127             coretypes::String::CreateFromUtf16(data.data(), data.size(), ctx, Runtime::GetCurrent()->GetPandaVM());
128         auto *second_string =
129             coretypes::String::CreateFromUtf16(data.data(), data.size(), ctx, Runtime::GetCurrent()->GetPandaVM());
130 
131         auto *interned_str1 = table.GetOrInternString(first_string, ctx);
132         auto *interned_str2 = table.GetOrInternString(second_string, ctx);
133         ASSERT_EQ(interned_str1, interned_str2);
134         ASSERT_EQ(table.Size(), 1);
135     }
136 
InternManyStrings()137     void InternManyStrings()
138     {
139         ScopedManagedCodeThread s(thread_);
140         static constexpr size_t iterations = 50;
141         auto table = StringTable();
142         std::vector<uint8_t> data {0x00};
143         const unsigned number_of_letters = 25;
144 
145         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
146         for (size_t i = 0; i < iterations; i++) {
147             data.insert(data.begin(), (('a' + i) % number_of_letters) + 1);
148             [[maybe_unused]] auto *first_pointer = table.GetOrInternString(AllocUtf8String(data), ctx);
149             [[maybe_unused]] auto *second_pointer =
150                 table.GetOrInternString(data.data(), utf::MUtf8ToUtf16Size(data.data()), ctx);
151             auto *third_pointer = table.GetOrInternString(AllocUtf8String(data), ctx);
152             ASSERT_EQ(first_pointer, second_pointer);
153             ASSERT_EQ(second_pointer, third_pointer);
154         }
155         ASSERT_EQ(table.Size(), iterations);
156     }
157 
SweepObjectInTable()158     void SweepObjectInTable()
159     {
160         ScopedManagedCodeThread s(thread_);
161         auto table = thread_->GetVM()->GetStringTable();
162         auto table_init_size = table->Size();
163         std::vector<uint8_t> data1 {0x01, 0x00};
164         std::vector<uint8_t> data2 {0x02, 0x00};
165         std::vector<uint8_t> data3 {0x03, 0x00};
166         const unsigned EXPECTED_TABLE_SIZE = 2;
167 
168         auto storage = thread_->GetVM()->GetGlobalObjectStorage();
169 
170         auto *s1 = AllocUtf8String(data1);
171         auto ref1 = storage->Add(s1, Reference::ObjectType::GLOBAL);
172         auto *s2 = AllocUtf8String(data2);
173         auto ref2 = storage->Add(s2, Reference::ObjectType::GLOBAL);
174         auto *s3 = AllocUtf8String(data3);
175         auto ref3 = storage->Add(s3, Reference::ObjectType::GLOBAL);
176 
177         auto panda_class_context = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
178         table->GetOrInternString(reinterpret_cast<coretypes::String *>(storage->Get(ref1)), panda_class_context);
179         table->GetOrInternString(reinterpret_cast<coretypes::String *>(storage->Get(ref2)), panda_class_context);
180         table->GetOrInternString(reinterpret_cast<coretypes::String *>(storage->Get(ref3)), panda_class_context);
181 
182         storage->Remove(ref2);
183 
184         thread_->GetVM()->GetGC()->WaitForGCInManaged(panda::GCTask(panda::GCTaskCause::EXPLICIT_CAUSE));
185         // genGC collect all heap for EXPLICIT_CAUSE
186         ASSERT_EQ(table->Size(), table_init_size + EXPECTED_TABLE_SIZE);
187     }
188 
InternTooLongString()189     void InternTooLongString()
190     {
191         ScopedManagedCodeThread s(thread_);
192         auto table = StringTable();
193         auto *runtime = Runtime::GetCurrent();
194         auto panda_class_context = runtime->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
195 
196         auto *thread = ManagedThread::GetCurrent();
197 
198         [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
199 
200         PandaVector<VMHandle<ObjectHeader>> objects;
201 
202         std::vector<uint8_t> string_data(10000U, 0x30);
203         string_data.push_back(0x00);
204 
205         auto fillHeap = [&string_data, &thread, &objects](bool is_movable) {
206             while (true) {
207                 auto *obj = AllocUtf8String(string_data, is_movable);
208                 if (obj == nullptr) {
209                     thread->ClearException();
210                     break;
211                 }
212                 objects.emplace_back(thread, obj);
213             }
214         };
215 
216         {
217             fillHeap(true);
218             auto *res = table.GetOrInternString(string_data.data(), string_data.size() - 1, panda_class_context);
219             ASSERT_EQ(res, nullptr);
220             ManagedThread::GetCurrent()->ClearException();
221         }
222 
223         {
224             panda_file::ItemContainer container;
225             panda_file::MemoryWriter writer;
226 
227             auto *string_item = container.GetOrCreateStringItem(reinterpret_cast<char *>(string_data.data()));
228 
229             container.Write(&writer);
230             auto data = writer.GetData();
231 
232             auto id = panda_file::File::EntityId(string_item->GetOffset());
233 
234             os::mem::ConstBytePtr ptr(reinterpret_cast<std::byte *>(data.data()), data.size(),
235                                       [](std::byte *, size_t) noexcept {});
236 
237             auto pf = panda_file::File::OpenFromMemory(std::move(ptr));
238 
239             fillHeap(false);
240             auto *res = table.GetOrInternInternalString(*pf.get(), id, panda_class_context);
241             ASSERT_EQ(res, nullptr);
242             ManagedThread::GetCurrent()->ClearException();
243         }
244     }
245 
246 protected:
247     panda::MTManagedThread *thread_;
248 };
249 }  // namespace panda::mem::test
250 
251 #endif  // STRING_TABLE_BASE_TEST_H