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