Line data Source code
1 : // Copyright 2018 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/api-inl.h"
6 : #include "src/api.h"
7 : #include "src/heap/spaces.h"
8 : #include "src/isolate.h"
9 : #include "src/objects-inl.h"
10 : #include "test/cctest/cctest.h"
11 : #include "test/cctest/heap/heap-tester.h"
12 : #include "test/cctest/heap/heap-utils.h"
13 :
14 : #define TEST_STR "tests are great!"
15 :
16 : namespace v8 {
17 : namespace internal {
18 : namespace heap {
19 :
20 : // Adapted from cctest/test-api.cc
21 : class TestOneByteResource : public v8::String::ExternalOneByteStringResource {
22 : public:
23 : explicit TestOneByteResource(const char* data, int* counter = nullptr,
24 : size_t offset = 0)
25 : : orig_data_(data),
26 : data_(data + offset),
27 30 : length_(strlen(data) - offset),
28 60 : counter_(counter) {}
29 :
30 60 : ~TestOneByteResource() override {
31 30 : i::DeleteArray(orig_data_);
32 30 : if (counter_ != nullptr) ++*counter_;
33 60 : }
34 :
35 85 : const char* data() const override { return data_; }
36 :
37 80 : size_t length() const override { return length_; }
38 :
39 : private:
40 : const char* orig_data_;
41 : const char* data_;
42 : size_t length_;
43 : int* counter_;
44 : };
45 :
46 28342 : TEST(ExternalString_ExternalBackingStoreSizeIncreases) {
47 5 : CcTest::InitializeVM();
48 5 : LocalContext env;
49 5 : v8::Isolate* isolate = env->GetIsolate();
50 10 : Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
51 : ExternalBackingStoreType type = ExternalBackingStoreType::kExternalString;
52 :
53 : const size_t backing_store_before =
54 5 : heap->old_space()->ExternalBackingStoreBytes(type);
55 :
56 : {
57 5 : v8::HandleScope handle_scope(isolate);
58 : v8::Local<v8::String> es = v8::String::NewExternalOneByte(
59 10 : isolate, new TestOneByteResource(i::StrDup(TEST_STR))).ToLocalChecked();
60 : USE(es);
61 :
62 : const size_t backing_store_after =
63 5 : heap->old_space()->ExternalBackingStoreBytes(type);
64 :
65 10 : CHECK_EQ(es->Length(), backing_store_after - backing_store_before);
66 5 : }
67 5 : }
68 :
69 28342 : TEST(ExternalString_ExternalBackingStoreSizeDecreases) {
70 : ManualGCScope manual_gc_scope;
71 5 : CcTest::InitializeVM();
72 10 : LocalContext env;
73 5 : v8::Isolate* isolate = env->GetIsolate();
74 10 : Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
75 : ExternalBackingStoreType type = ExternalBackingStoreType::kExternalString;
76 :
77 : const size_t backing_store_before =
78 5 : heap->old_space()->ExternalBackingStoreBytes(type);
79 :
80 : {
81 5 : v8::HandleScope handle_scope(isolate);
82 : v8::Local<v8::String> es = v8::String::NewExternalOneByte(
83 10 : isolate, new TestOneByteResource(i::StrDup(TEST_STR))).ToLocalChecked();
84 5 : USE(es);
85 : }
86 :
87 5 : heap::GcAndSweep(heap, OLD_SPACE);
88 :
89 : const size_t backing_store_after =
90 5 : heap->old_space()->ExternalBackingStoreBytes(type);
91 :
92 5 : CHECK_EQ(0, backing_store_after - backing_store_before);
93 5 : }
94 :
95 28342 : TEST(ExternalString_ExternalBackingStoreSizeIncreasesMarkCompact) {
96 5 : if (FLAG_never_compact) return;
97 : ManualGCScope manual_gc_scope;
98 5 : FLAG_manual_evacuation_candidates_selection = true;
99 5 : CcTest::InitializeVM();
100 10 : LocalContext env;
101 5 : v8::Isolate* isolate = env->GetIsolate();
102 20 : Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
103 5 : heap::AbandonCurrentlyFreeMemory(heap->old_space());
104 : ExternalBackingStoreType type = ExternalBackingStoreType::kExternalString;
105 :
106 : const size_t backing_store_before =
107 5 : heap->old_space()->ExternalBackingStoreBytes(type);
108 :
109 : {
110 5 : v8::HandleScope handle_scope(isolate);
111 : v8::Local<v8::String> es = v8::String::NewExternalOneByte(
112 10 : isolate, new TestOneByteResource(i::StrDup(TEST_STR))).ToLocalChecked();
113 : v8::internal::Handle<v8::internal::String> esh = v8::Utils::OpenHandle(*es);
114 :
115 : Page* page_before_gc = Page::FromHeapObject(*esh);
116 5 : heap::ForceEvacuationCandidate(page_before_gc);
117 :
118 5 : CcTest::CollectAllGarbage();
119 :
120 : const size_t backing_store_after =
121 5 : heap->old_space()->ExternalBackingStoreBytes(type);
122 10 : CHECK_EQ(es->Length(), backing_store_after - backing_store_before);
123 : }
124 :
125 5 : heap::GcAndSweep(heap, OLD_SPACE);
126 : const size_t backing_store_after =
127 5 : heap->old_space()->ExternalBackingStoreBytes(type);
128 5 : CHECK_EQ(0, backing_store_after - backing_store_before);
129 : }
130 :
131 28342 : TEST(ExternalString_ExternalBackingStoreSizeIncreasesAfterExternalization) {
132 5 : CcTest::InitializeVM();
133 5 : LocalContext env;
134 5 : v8::Isolate* isolate = env->GetIsolate();
135 30 : Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
136 : ExternalBackingStoreType type = ExternalBackingStoreType::kExternalString;
137 : size_t old_backing_store_before = 0, new_backing_store_before = 0;
138 :
139 : {
140 5 : v8::HandleScope handle_scope(isolate);
141 :
142 : new_backing_store_before =
143 5 : heap->new_space()->ExternalBackingStoreBytes(type);
144 : old_backing_store_before =
145 5 : heap->old_space()->ExternalBackingStoreBytes(type);
146 :
147 : // Allocate normal string in the new gen.
148 : v8::Local<v8::String> str =
149 : v8::String::NewFromUtf8(isolate, TEST_STR, v8::NewStringType::kNormal)
150 5 : .ToLocalChecked();
151 :
152 10 : CHECK_EQ(0, heap->new_space()->ExternalBackingStoreBytes(type) -
153 : new_backing_store_before);
154 :
155 : // Trigger GCs so that the newly allocated string moves to old gen.
156 5 : heap::GcAndSweep(heap, NEW_SPACE); // in survivor space now
157 5 : heap::GcAndSweep(heap, NEW_SPACE); // in old gen now
158 :
159 : bool success =
160 10 : str->MakeExternal(new TestOneByteResource(i::StrDup(TEST_STR)));
161 5 : CHECK(success);
162 :
163 10 : CHECK_EQ(str->Length(), heap->old_space()->ExternalBackingStoreBytes(type) -
164 5 : old_backing_store_before);
165 : }
166 :
167 5 : heap::GcAndSweep(heap, OLD_SPACE);
168 :
169 10 : CHECK_EQ(0, heap->old_space()->ExternalBackingStoreBytes(type) -
170 5 : old_backing_store_before);
171 5 : }
172 :
173 28342 : TEST(ExternalString_PromotedThinString) {
174 : ManualGCScope manual_gc_scope;
175 5 : CcTest::InitializeVM();
176 10 : LocalContext env;
177 5 : v8::Isolate* isolate = env->GetIsolate();
178 : i::Isolate* i_isolate = CcTest::i_isolate();
179 : i::Factory* factory = i_isolate->factory();
180 5 : Heap* heap = i_isolate->heap();
181 :
182 : {
183 5 : v8::HandleScope handle_scope(isolate);
184 :
185 : // New external string in the old space.
186 : v8::internal::Handle<v8::internal::String> string1 =
187 : factory
188 : ->NewExternalStringFromOneByte(
189 5 : new TestOneByteResource(i::StrDup(TEST_STR)))
190 10 : .ToHandleChecked();
191 :
192 : // Internalize external string.
193 5 : i::Handle<i::String> isymbol1 = factory->InternalizeString(string1);
194 10 : CHECK(isymbol1->IsInternalizedString());
195 10 : CHECK(string1->IsExternalString());
196 5 : CHECK(!heap->InNewSpace(*isymbol1));
197 :
198 : // New external string in the young space. This string has the same content
199 : // as the previous one (that was already internalized).
200 : v8::Local<v8::String> string2 =
201 : v8::String::NewFromUtf8(isolate, TEST_STR, v8::NewStringType::kNormal)
202 5 : .ToLocalChecked();
203 : bool success =
204 10 : string2->MakeExternal(new TestOneByteResource(i::StrDup(TEST_STR)));
205 5 : CHECK(success);
206 :
207 : // Internalize (it will create a thin string in the new space).
208 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string2);
209 5 : i::Handle<i::String> isymbol2 = factory->InternalizeString(istring);
210 10 : CHECK(isymbol2->IsInternalizedString());
211 10 : CHECK(istring->IsThinString());
212 5 : CHECK(heap->InNewSpace(*istring));
213 :
214 : // Collect thin string. References to the thin string will be updated to
215 : // point to the actual external string in the old space.
216 5 : heap::GcAndSweep(heap, NEW_SPACE);
217 :
218 : USE(isymbol1);
219 5 : USE(isymbol2);
220 : }
221 5 : }
222 : } // namespace heap
223 : } // namespace internal
224 85011 : } // namespace v8
225 :
226 : #undef TEST_STR
|