• 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 "gtest/gtest.h"
17 #include "runtime/include/coretypes/string.h"
18 #include "runtime/include/runtime.h"
19 #include "runtime/include/thread.h"
20 #include "runtime/include/gc_task.h"
21 #include "runtime/include/panda_vm.h"
22 #include "runtime/handle_base-inl.h"
23 
24 namespace panda::mem::test {
25 
26 class StringTableTest : public testing::Test {
27 public:
StringTableTest()28     StringTableTest()
29     {
30         RuntimeOptions options;
31         options.SetShouldLoadBootPandaFiles(false);
32         options.SetShouldInitializeIntrinsics(false);
33 
34         options.SetCompilerEnableJit(false);
35         Runtime::Create(options);
36     }
37 
~StringTableTest()38     ~StringTableTest() override
39     {
40         Runtime::Destroy();
41     }
42 
AllocUtf8String(std::vector<uint8_t> data)43     static coretypes::String *AllocUtf8String(std::vector<uint8_t> data)
44     {
45         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
46         return coretypes::String::CreateFromMUtf8(data.data(), utf::MUtf8ToUtf16Size(data.data()), ctx,
47                                                   Runtime::GetCurrent()->GetPandaVM());
48     }
49 
SetUp()50     void SetUp() override
51     {
52         thread_ = panda::MTManagedThread::GetCurrent();
53         thread_->ManagedCodeBegin();
54     }
55 
TearDown()56     void TearDown() override
57     {
58         thread_->ManagedCodeEnd();
59     }
60 
61 protected:
62     panda::MTManagedThread *thread_ {nullptr};
63 };
64 
TEST_F(StringTableTest,EmptyTable)65 TEST_F(StringTableTest, EmptyTable)
66 {
67     auto table = StringTable();
68     ASSERT_EQ(table.Size(), 0);
69 }
70 
TEST_F(StringTableTest,InternCompressedUtf8AndString)71 TEST_F(StringTableTest, InternCompressedUtf8AndString)
72 {
73     auto table = StringTable();
74     std::vector<uint8_t> data {0x01, 0x02, 0x03, 0x00};
75     auto *string = AllocUtf8String(data);
76     auto *interned_str1 =
77         table.GetOrInternString(data.data(), data.size() - 1,
78                                 Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY));
79     auto *interned_str2 = table.GetOrInternString(
80         string, Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY));
81     ASSERT_EQ(interned_str1, interned_str2);
82     ASSERT_EQ(table.Size(), 1);
83 }
84 
TEST_F(StringTableTest,InternUncompressedUtf8AndString)85 TEST_F(StringTableTest, InternUncompressedUtf8AndString)
86 {
87     auto table = StringTable();
88     std::vector<uint8_t> data {0xc2, 0xa7, 0x34, 0x00};
89     auto *string = AllocUtf8String(data);
90     auto *interned_str1 = table.GetOrInternString(
91         data.data(), 2, Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY));
92     auto *interned_str2 = table.GetOrInternString(
93         string, Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY));
94     ASSERT_EQ(interned_str1, interned_str2);
95     ASSERT_EQ(table.Size(), 1);
96 }
97 
TEST_F(StringTableTest,InternTheSameUtf16String)98 TEST_F(StringTableTest, InternTheSameUtf16String)
99 {
100     auto table = StringTable();
101     std::vector<uint16_t> data {0xffc3, 0x33, 0x00};
102 
103     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
104     auto *first_string =
105         coretypes::String::CreateFromUtf16(data.data(), data.size(), ctx, Runtime::GetCurrent()->GetPandaVM());
106     auto *second_string =
107         coretypes::String::CreateFromUtf16(data.data(), data.size(), ctx, Runtime::GetCurrent()->GetPandaVM());
108 
109     auto *interned_str1 = table.GetOrInternString(first_string, ctx);
110     auto *interned_str2 = table.GetOrInternString(second_string, ctx);
111     ASSERT_EQ(interned_str1, interned_str2);
112     ASSERT_EQ(table.Size(), 1);
113 }
114 
TEST_F(StringTableTest,InternManyStrings)115 TEST_F(StringTableTest, InternManyStrings)
116 {
117     static constexpr size_t ITERATIONS = 50;
118     auto table = StringTable();
119     std::vector<uint8_t> data {0x00};
120 
121     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
122     for (size_t i = 0; i < ITERATIONS; i++) {
123         data.insert(data.begin(), (('a' + i) % 25) + 1);
124         [[maybe_unused]] auto *first_pointer = table.GetOrInternString(AllocUtf8String(data), ctx);
125         [[maybe_unused]] auto *second_pointer =
126             table.GetOrInternString(data.data(), utf::MUtf8ToUtf16Size(data.data()), ctx);
127         auto *third_pointer = table.GetOrInternString(AllocUtf8String(data), ctx);
128         ASSERT_EQ(first_pointer, second_pointer);
129         ASSERT_EQ(second_pointer, third_pointer);
130     }
131     ASSERT_EQ(table.Size(), ITERATIONS);
132 }
133 
TEST_F(StringTableTest,SweepObjectInTable)134 TEST_F(StringTableTest, SweepObjectInTable)
135 {
136     auto table = thread_->GetVM()->GetStringTable();
137     auto table_init_size = table->Size();
138     std::vector<uint8_t> data1 {0x01, 0x00};
139     std::vector<uint8_t> data2 {0x02, 0x00};
140     std::vector<uint8_t> data3 {0x03, 0x00};
141     auto *s1 = AllocUtf8String(data1);
142     auto *s2 = AllocUtf8String(data2);
143     auto *s3 = AllocUtf8String(data3);
144     auto thread = ManagedThread::GetCurrent();
145     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
146     VMHandle<coretypes::String> s2h(thread, s2);
147     VMHandle<coretypes::String> s3h(thread, s3);
148     table->GetOrInternString(s1, Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY));
149     table->GetOrInternString(s2, Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY));
150     table->GetOrInternString(s3, Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY));
151     s1->SetMarkedForGC();
152     s3->SetMarkedForGC();
153     ASSERT_FALSE(s2->IsMarkedForGC());
154     thread_->GetVM()->GetGC()->WaitForGCInManaged(panda::GCTask(panda::GCTaskCause::EXPLICIT_CAUSE));
155     // There is no guarantee that Tenured GC will be called - so GE instead of EQ
156     ASSERT_GE(table->Size(), table_init_size + 2);
157 }
158 
159 }  // namespace panda::mem::test
160