9b78e758af
Both NewSpace and NewLargeObjectSpace aren't used with FLAG_single_generation enabled. So far both spaces still existed but weren't used in this mode. This CL makes both spaces optional, which ensure that we do not inadvertently create objects in them or use them in any other way. Bug: v8:11644 Change-Id: I52a449c62e9d3df126c95419433d2abbd75539a5 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2862768 Commit-Queue: Dominik Inführ <dinfuehr@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Cr-Commit-Position: refs/heads/master@{#74345}
229 lines
7.4 KiB
C++
229 lines
7.4 KiB
C++
// Copyright 2018 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/api/api-inl.h"
|
|
#include "src/api/api.h"
|
|
#include "src/execution/isolate.h"
|
|
#include "src/heap/heap-inl.h"
|
|
#include "src/heap/spaces.h"
|
|
#include "src/objects/objects-inl.h"
|
|
#include "test/cctest/cctest.h"
|
|
#include "test/cctest/heap/heap-tester.h"
|
|
#include "test/cctest/heap/heap-utils.h"
|
|
|
|
#define TEST_STR "tests are great!"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace heap {
|
|
|
|
// Adapted from cctest/test-api.cc
|
|
class TestOneByteResource : public v8::String::ExternalOneByteStringResource {
|
|
public:
|
|
explicit TestOneByteResource(const char* data, int* counter = nullptr,
|
|
size_t offset = 0)
|
|
: orig_data_(data),
|
|
data_(data + offset),
|
|
length_(strlen(data) - offset),
|
|
counter_(counter) {}
|
|
|
|
~TestOneByteResource() override {
|
|
i::DeleteArray(orig_data_);
|
|
if (counter_ != nullptr) ++*counter_;
|
|
}
|
|
|
|
const char* data() const override { return data_; }
|
|
|
|
size_t length() const override { return length_; }
|
|
|
|
private:
|
|
const char* orig_data_;
|
|
const char* data_;
|
|
size_t length_;
|
|
int* counter_;
|
|
};
|
|
|
|
TEST(ExternalString_ExternalBackingStoreSizeIncreases) {
|
|
CcTest::InitializeVM();
|
|
LocalContext env;
|
|
v8::Isolate* isolate = env->GetIsolate();
|
|
Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
|
|
ExternalBackingStoreType type = ExternalBackingStoreType::kExternalString;
|
|
|
|
const size_t backing_store_before =
|
|
heap->old_space()->ExternalBackingStoreBytes(type);
|
|
|
|
{
|
|
v8::HandleScope handle_scope(isolate);
|
|
v8::Local<v8::String> es = v8::String::NewExternalOneByte(
|
|
isolate, new TestOneByteResource(i::StrDup(TEST_STR))).ToLocalChecked();
|
|
USE(es);
|
|
|
|
const size_t backing_store_after =
|
|
heap->old_space()->ExternalBackingStoreBytes(type);
|
|
|
|
CHECK_EQ(es->Length(), backing_store_after - backing_store_before);
|
|
}
|
|
}
|
|
|
|
TEST(ExternalString_ExternalBackingStoreSizeDecreases) {
|
|
ManualGCScope manual_gc_scope;
|
|
CcTest::InitializeVM();
|
|
LocalContext env;
|
|
v8::Isolate* isolate = env->GetIsolate();
|
|
Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
|
|
ExternalBackingStoreType type = ExternalBackingStoreType::kExternalString;
|
|
|
|
const size_t backing_store_before =
|
|
heap->old_space()->ExternalBackingStoreBytes(type);
|
|
|
|
{
|
|
v8::HandleScope handle_scope(isolate);
|
|
v8::Local<v8::String> es = v8::String::NewExternalOneByte(
|
|
isolate, new TestOneByteResource(i::StrDup(TEST_STR))).ToLocalChecked();
|
|
USE(es);
|
|
}
|
|
|
|
heap::GcAndSweep(heap, OLD_SPACE);
|
|
|
|
const size_t backing_store_after =
|
|
heap->old_space()->ExternalBackingStoreBytes(type);
|
|
|
|
CHECK_EQ(0, backing_store_after - backing_store_before);
|
|
}
|
|
|
|
TEST(ExternalString_ExternalBackingStoreSizeIncreasesMarkCompact) {
|
|
if (FLAG_never_compact) return;
|
|
ManualGCScope manual_gc_scope;
|
|
FLAG_manual_evacuation_candidates_selection = true;
|
|
CcTest::InitializeVM();
|
|
LocalContext env;
|
|
v8::Isolate* isolate = env->GetIsolate();
|
|
Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
|
|
heap::AbandonCurrentlyFreeMemory(heap->old_space());
|
|
ExternalBackingStoreType type = ExternalBackingStoreType::kExternalString;
|
|
|
|
const size_t backing_store_before =
|
|
heap->old_space()->ExternalBackingStoreBytes(type);
|
|
|
|
{
|
|
v8::HandleScope handle_scope(isolate);
|
|
v8::Local<v8::String> es = v8::String::NewExternalOneByte(
|
|
isolate, new TestOneByteResource(i::StrDup(TEST_STR))).ToLocalChecked();
|
|
v8::internal::Handle<v8::internal::String> esh = v8::Utils::OpenHandle(*es);
|
|
|
|
Page* page_before_gc = Page::FromHeapObject(*esh);
|
|
heap::ForceEvacuationCandidate(page_before_gc);
|
|
|
|
CcTest::CollectAllGarbage();
|
|
|
|
const size_t backing_store_after =
|
|
heap->old_space()->ExternalBackingStoreBytes(type);
|
|
CHECK_EQ(es->Length(), backing_store_after - backing_store_before);
|
|
}
|
|
|
|
heap::GcAndSweep(heap, OLD_SPACE);
|
|
const size_t backing_store_after =
|
|
heap->old_space()->ExternalBackingStoreBytes(type);
|
|
CHECK_EQ(0, backing_store_after - backing_store_before);
|
|
}
|
|
|
|
TEST(ExternalString_ExternalBackingStoreSizeIncreasesAfterExternalization) {
|
|
if (FLAG_single_generation) return;
|
|
ManualGCScope manual_gc_scope;
|
|
CcTest::InitializeVM();
|
|
LocalContext env;
|
|
v8::Isolate* isolate = env->GetIsolate();
|
|
Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
|
|
ExternalBackingStoreType type = ExternalBackingStoreType::kExternalString;
|
|
size_t old_backing_store_before = 0, new_backing_store_before = 0;
|
|
|
|
{
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
new_backing_store_before =
|
|
heap->new_space()->ExternalBackingStoreBytes(type);
|
|
old_backing_store_before =
|
|
heap->old_space()->ExternalBackingStoreBytes(type);
|
|
|
|
// Allocate normal string in the new gen.
|
|
v8::Local<v8::String> str =
|
|
v8::String::NewFromUtf8Literal(isolate, TEST_STR);
|
|
|
|
CHECK_EQ(0, heap->new_space()->ExternalBackingStoreBytes(type) -
|
|
new_backing_store_before);
|
|
|
|
// Trigger GCs so that the newly allocated string moves to old gen.
|
|
heap::GcAndSweep(heap, NEW_SPACE); // in survivor space now
|
|
heap::GcAndSweep(heap, NEW_SPACE); // in old gen now
|
|
|
|
bool success =
|
|
str->MakeExternal(new TestOneByteResource(i::StrDup(TEST_STR)));
|
|
CHECK(success);
|
|
|
|
CHECK_EQ(str->Length(), heap->old_space()->ExternalBackingStoreBytes(type) -
|
|
old_backing_store_before);
|
|
}
|
|
|
|
heap::GcAndSweep(heap, OLD_SPACE);
|
|
|
|
CHECK_EQ(0, heap->old_space()->ExternalBackingStoreBytes(type) -
|
|
old_backing_store_before);
|
|
}
|
|
|
|
TEST(ExternalString_PromotedThinString) {
|
|
if (FLAG_single_generation) return;
|
|
ManualGCScope manual_gc_scope;
|
|
CcTest::InitializeVM();
|
|
LocalContext env;
|
|
v8::Isolate* isolate = env->GetIsolate();
|
|
i::Isolate* i_isolate = CcTest::i_isolate();
|
|
i::Factory* factory = i_isolate->factory();
|
|
Heap* heap = i_isolate->heap();
|
|
|
|
{
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
// New external string in the old space.
|
|
v8::internal::Handle<v8::internal::String> string1 =
|
|
factory
|
|
->NewExternalStringFromOneByte(
|
|
new TestOneByteResource(i::StrDup(TEST_STR)))
|
|
.ToHandleChecked();
|
|
|
|
// Internalize external string.
|
|
i::Handle<i::String> isymbol1 = factory->InternalizeString(string1);
|
|
CHECK(isymbol1->IsInternalizedString());
|
|
CHECK(string1->IsExternalString());
|
|
CHECK(!heap->InYoungGeneration(*isymbol1));
|
|
|
|
// New external string in the young space. This string has the same content
|
|
// as the previous one (that was already internalized).
|
|
v8::Local<v8::String> string2 =
|
|
v8::String::NewFromUtf8Literal(isolate, TEST_STR);
|
|
bool success =
|
|
string2->MakeExternal(new TestOneByteResource(i::StrDup(TEST_STR)));
|
|
CHECK(success);
|
|
|
|
// Internalize (it will create a thin string in the new space).
|
|
i::Handle<i::String> istring = v8::Utils::OpenHandle(*string2);
|
|
i::Handle<i::String> isymbol2 = factory->InternalizeString(istring);
|
|
CHECK(isymbol2->IsInternalizedString());
|
|
CHECK(istring->IsThinString());
|
|
CHECK(heap->InYoungGeneration(*istring));
|
|
|
|
// Collect thin string. References to the thin string will be updated to
|
|
// point to the actual external string in the old space.
|
|
heap::GcAndSweep(heap, NEW_SPACE);
|
|
|
|
USE(isymbol1);
|
|
USE(isymbol2);
|
|
}
|
|
}
|
|
} // namespace heap
|
|
} // namespace internal
|
|
} // namespace v8
|
|
|
|
#undef TEST_STR
|