[test] Move cctest/test-code-pages to unittests

... /codegen/code-pages-unittest.

Bug: v8:12781
Change-Id: Ied73476c801257fc9497b5101ea49a98b657f8ea
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3599404
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: 王澳 <wangao.james@bytedance.com>
Cr-Commit-Position: refs/heads/main@{#80134}
This commit is contained in:
jameslahm 2022-04-23 10:53:43 +08:00 committed by V8 LUCI CQ
parent 35898f2ad6
commit c2cd3e64f9
3 changed files with 146 additions and 150 deletions

View File

@ -197,7 +197,6 @@ v8_source_set("cctest_sources") {
"test-bignum.cc",
"test-circular-queue.cc",
"test-code-layout.cc",
"test-code-pages.cc",
"test-code-stub-assembler.cc",
"test-concurrent-prototype.cc",
"test-concurrent-transition-array.cc",

View File

@ -240,6 +240,7 @@ v8_source_set("unittests_sources") {
"base/vlq-base64-unittest.cc",
"base/vlq-unittest.cc",
"codegen/aligned-slot-allocator-unittest.cc",
"codegen/code-pages-unittest.cc",
"codegen/code-stub-assembler-unittest.cc",
"codegen/code-stub-assembler-unittest.h",
"codegen/register-configuration-unittest.cc",

View File

@ -1,4 +1,4 @@
// Copyright 2019 the V8 project authors. All rights reserved.
// Copyright 2022 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.
@ -12,9 +12,13 @@
#include "src/heap/memory-allocator.h"
#include "src/heap/spaces.h"
#include "src/libsampler/sampler.h"
#include "test/cctest/cctest.h"
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
using CodePagesTest = TestWithContext;
namespace internal {
namespace test_code_pages {
@ -45,7 +49,7 @@ static const char* foo_source = R"(
std::string getFooCode(int n) {
constexpr size_t kMaxSize = 512;
char foo_replaced[kMaxSize];
CHECK_LE(n, 999999);
EXPECT_LE(n, 999999);
snprintf(foo_replaced, kMaxSize, foo_source, n, n, n, n, n, n);
return std::string(foo_replaced);
@ -90,98 +94,86 @@ bool PagesContainsAddress(std::vector<MemoryRange>* pages,
} // namespace
TEST(CodeRangeCorrectContents) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
if (!i_isolate->RequiresCodeRange()) return;
TEST_F(CodePagesTest, CodeRangeCorrectContents) {
if (!i_isolate()->RequiresCodeRange()) return;
std::vector<MemoryRange>* pages = i_isolate->GetCodePages();
std::vector<MemoryRange>* pages = i_isolate()->GetCodePages();
const base::AddressRegion& code_region = i_isolate->heap()->code_region();
CHECK(!code_region.is_empty());
const base::AddressRegion& code_region = i_isolate()->heap()->code_region();
EXPECT_TRUE(!code_region.is_empty());
// We should only have the code range and the embedded code range.
CHECK_EQ(2, pages->size());
CHECK(PagesHasExactPage(pages, code_region.begin(), code_region.size()));
CHECK(PagesHasExactPage(
pages, reinterpret_cast<Address>(i_isolate->CurrentEmbeddedBlobCode()),
i_isolate->CurrentEmbeddedBlobCodeSize()));
if (i_isolate->is_short_builtin_calls_enabled()) {
EXPECT_EQ(2u, pages->size());
EXPECT_TRUE(
PagesHasExactPage(pages, code_region.begin(), code_region.size()));
EXPECT_TRUE(PagesHasExactPage(
pages, reinterpret_cast<Address>(i_isolate()->CurrentEmbeddedBlobCode()),
i_isolate()->CurrentEmbeddedBlobCodeSize()));
if (i_isolate()->is_short_builtin_calls_enabled()) {
// In this case embedded blob code must be included via code_region.
CHECK(PagesContainsRange(
pages, reinterpret_cast<Address>(i_isolate->embedded_blob_code()),
i_isolate->embedded_blob_code_size()));
EXPECT_TRUE(PagesContainsRange(
pages, reinterpret_cast<Address>(i_isolate()->embedded_blob_code()),
i_isolate()->embedded_blob_code_size()));
} else {
CHECK(PagesHasExactPage(
pages, reinterpret_cast<Address>(i_isolate->embedded_blob_code()),
i_isolate->embedded_blob_code_size()));
EXPECT_TRUE(PagesHasExactPage(
pages, reinterpret_cast<Address>(i_isolate()->embedded_blob_code()),
i_isolate()->embedded_blob_code_size()));
}
}
TEST(CodePagesCorrectContents) {
TEST_F(CodePagesTest, CodePagesCorrectContents) {
if (!kHaveCodePages) return;
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
std::vector<MemoryRange>* pages = i_isolate->GetCodePages();
std::vector<MemoryRange>* pages = i_isolate()->GetCodePages();
// There might be other pages already.
CHECK_GE(pages->size(), 1);
EXPECT_GE(pages->size(), 1u);
const base::AddressRegion& code_region = i_isolate->heap()->code_region();
CHECK(code_region.is_empty());
const base::AddressRegion& code_region = i_isolate()->heap()->code_region();
EXPECT_TRUE(code_region.is_empty());
// We should have the embedded code range even when there is no regular code
// range.
CHECK(PagesHasExactPage(
pages, reinterpret_cast<Address>(i_isolate->embedded_blob_code()),
i_isolate->embedded_blob_code_size()));
EXPECT_TRUE(PagesHasExactPage(
pages, reinterpret_cast<Address>(i_isolate()->embedded_blob_code()),
i_isolate()->embedded_blob_code_size()));
}
TEST(OptimizedCodeWithCodeRange) {
TEST_F(CodePagesTest, OptimizedCodeWithCodeRange) {
FLAG_allow_natives_syntax = true;
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
if (!i_isolate->RequiresCodeRange()) return;
if (!i_isolate()->RequiresCodeRange()) return;
HandleScope scope(i_isolate);
HandleScope scope(i_isolate());
std::string foo_str = getFooCode(1);
CompileRun(foo_str.c_str());
RunJS(foo_str.c_str());
v8::Local<v8::Function> local_foo = v8::Local<v8::Function>::Cast(
env.local()->Global()->Get(env.local(), v8_str("foo1")).ToLocalChecked());
context()->Global()->Get(context(), NewString("foo1")).ToLocalChecked());
Handle<JSFunction> foo =
Handle<JSFunction>::cast(v8::Utils::OpenHandle(*local_foo));
AbstractCode abstract_code = foo->abstract_code(i_isolate);
AbstractCode abstract_code = foo->abstract_code(i_isolate());
// We don't produce optimized code when run with --no-opt.
if (!abstract_code.IsCode() && FLAG_opt == false) return;
CHECK(abstract_code.IsCode());
EXPECT_TRUE(abstract_code.IsCode());
Code foo_code = abstract_code.GetCode();
CHECK(i_isolate->heap()->InSpace(foo_code, CODE_SPACE));
EXPECT_TRUE(i_isolate()->heap()->InSpace(foo_code, CODE_SPACE));
std::vector<MemoryRange>* pages = i_isolate->GetCodePages();
CHECK(PagesContainsAddress(pages, foo_code.address()));
std::vector<MemoryRange>* pages = i_isolate()->GetCodePages();
EXPECT_TRUE(PagesContainsAddress(pages, foo_code.address()));
}
TEST(OptimizedCodeWithCodePages) {
TEST_F(CodePagesTest, OptimizedCodeWithCodePages) {
if (!kHaveCodePages) return;
// We don't want incremental marking to start which could cause the code to
// not be collected on the CollectGarbage() call.
ManualGCScope manual_gc_scope;
ManualGCScope manual_gc_scope(i_isolate());
FLAG_allow_natives_syntax = true;
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
const void* created_page = nullptr;
int num_foos_created = 0;
{
HandleScope scope(i_isolate);
HandleScope scope(i_isolate());
size_t num_code_pages = 0;
size_t initial_num_code_pages = 0;
@ -192,12 +184,12 @@ TEST(OptimizedCodeWithCodePages) {
std::string foo_str = getFooCode(n);
char foo_name[10];
snprintf(foo_name, sizeof(foo_name), "foo%d", n);
CompileRun(foo_str.c_str());
v8::Local<v8::Function> local_foo =
v8::Local<v8::Function>::Cast(env.local()
->Global()
->Get(env.local(), v8_str(foo_name))
.ToLocalChecked());
RunJS(foo_str.c_str());
v8::Local<v8::Function> local_foo = v8::Local<v8::Function>::Cast(
context()
->Global()
->Get(context(), NewString(foo_name))
.ToLocalChecked());
Handle<JSFunction> foo =
Handle<JSFunction>::cast(v8::Utils::OpenHandle(*local_foo));
@ -205,21 +197,21 @@ TEST(OptimizedCodeWithCodePages) {
// --always-sparkplug (if this check fails, we'll have to re-think this
// test).
if (foo->shared().HasBaselineCode()) {
CHECK(FLAG_always_sparkplug);
EXPECT_TRUE(FLAG_always_sparkplug);
return;
}
AbstractCode abstract_code = foo->abstract_code(i_isolate);
AbstractCode abstract_code = foo->abstract_code(i_isolate());
// We don't produce optimized code when run with --no-opt.
if (!abstract_code.IsCode() && FLAG_opt == false) return;
CHECK(abstract_code.IsCode());
EXPECT_TRUE(abstract_code.IsCode());
Code foo_code = abstract_code.GetCode();
CHECK(i_isolate->heap()->InSpace(foo_code, CODE_SPACE));
EXPECT_TRUE(i_isolate()->heap()->InSpace(foo_code, CODE_SPACE));
// Check that the generated code ended up in one of the code pages
// returned by GetCodePages().
byte* foo_code_ptr = reinterpret_cast<byte*>(foo_code.address());
std::vector<MemoryRange>* pages = i_isolate->GetCodePages();
std::vector<MemoryRange>* pages = i_isolate()->GetCodePages();
// Wait until after we have created the first function to take the initial
// number of pages so that this test isn't brittle to irrelevant
@ -237,7 +229,7 @@ TEST(OptimizedCodeWithCodePages) {
const byte* page_end = page_start + r.length_in_bytes;
return foo_code_ptr >= page_start && foo_code_ptr < page_end;
});
CHECK_NE(it, pages->end());
EXPECT_NE(it, pages->end());
// Store the page that was created just for our functions - we expect it
// to be removed later.
@ -253,39 +245,36 @@ TEST(OptimizedCodeWithCodePages) {
// Now delete all our foos and force a GC and check that the page is removed
// from the list.
{
HandleScope scope(i_isolate);
HandleScope scope(i_isolate());
for (int n = 0; n < num_foos_created; n++) {
char foo_name[10];
snprintf(foo_name, sizeof(foo_name), "foo%d", n);
env.local()
context()
->Global()
->Set(env.local(), v8_str(foo_name), Undefined(isolate))
->Set(context(), NewString(foo_name), Undefined(isolate()))
.Check();
}
}
CcTest::CollectGarbage(CODE_SPACE);
CollectGarbage(CODE_SPACE);
std::vector<MemoryRange>* pages = i_isolate->GetCodePages();
std::vector<MemoryRange>* pages = i_isolate()->GetCodePages();
auto it = std::find_if(
pages->begin(), pages->end(),
[created_page](const MemoryRange& r) { return r.start == created_page; });
CHECK_EQ(it, pages->end());
EXPECT_EQ(it, pages->end());
}
TEST(LargeCodeObject) {
TEST_F(CodePagesTest, LargeCodeObject) {
// We don't want incremental marking to start which could cause the code to
// not be collected on the CollectGarbage() call.
ManualGCScope manual_gc_scope;
ManualGCScope manual_gc_scope(i_isolate());
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
if (!i_isolate->RequiresCodeRange() && !kHaveCodePages) return;
if (!i_isolate()->RequiresCodeRange() && !kHaveCodePages) return;
// Create a big function that ends up in CODE_LO_SPACE.
const int instruction_size = Page::kPageSize + 1;
CHECK_GT(instruction_size, MemoryChunkLayout::MaxRegularCodeObjectSize());
EXPECT_GT(instruction_size, MemoryChunkLayout::MaxRegularCodeObjectSize());
std::unique_ptr<byte[]> instructions(new byte[instruction_size]);
CodeDesc desc;
@ -301,30 +290,32 @@ TEST(LargeCodeObject) {
Address stale_code_address;
{
HandleScope scope(i_isolate);
HandleScope scope(i_isolate());
Handle<Code> foo_code =
Factory::CodeBuilder(i_isolate, desc, CodeKind::WASM_FUNCTION).Build();
Factory::CodeBuilder(i_isolate(), desc, CodeKind::WASM_FUNCTION)
.Build();
CHECK(i_isolate->heap()->InSpace(*foo_code, CODE_LO_SPACE));
EXPECT_TRUE(i_isolate()->heap()->InSpace(*foo_code, CODE_LO_SPACE));
std::vector<MemoryRange>* pages = i_isolate->GetCodePages();
std::vector<MemoryRange>* pages = i_isolate()->GetCodePages();
if (i_isolate->RequiresCodeRange()) {
CHECK(PagesContainsAddress(pages, foo_code->address()));
if (i_isolate()->RequiresCodeRange()) {
EXPECT_TRUE(PagesContainsAddress(pages, foo_code->address()));
} else {
CHECK(PagesHasExactPage(pages, foo_code->address()));
EXPECT_TRUE(PagesHasExactPage(pages, foo_code->address()));
}
stale_code_address = foo_code->address();
}
// Delete the large code object.
CcTest::CollectGarbage(CODE_LO_SPACE);
CHECK(!i_isolate->heap()->InSpaceSlow(stale_code_address, CODE_LO_SPACE));
CollectGarbage(CODE_LO_SPACE);
EXPECT_TRUE(
!i_isolate()->heap()->InSpaceSlow(stale_code_address, CODE_LO_SPACE));
// Check that it was removed from CodePages.
std::vector<MemoryRange>* pages = i_isolate->GetCodePages();
CHECK(!PagesHasExactPage(pages, stale_code_address));
std::vector<MemoryRange>* pages = i_isolate()->GetCodePages();
EXPECT_TRUE(!PagesHasExactPage(pages, stale_code_address));
}
static constexpr size_t kBufSize = v8::Isolate::kMinCodePagesBufferSize;
@ -338,7 +329,7 @@ class SignalSender : public sampler::Sampler {
MemoryRange* code_pages_copy = code_pages_copy_.load();
CHECK_NOT_NULL(code_pages_copy);
size_t num_pages = isolate_->CopyCodePages(kBufSize, code_pages_copy);
CHECK_LE(num_pages, kBufSize);
EXPECT_LE(num_pages, kBufSize);
sample_semaphore_.Signal();
}
@ -376,7 +367,7 @@ class SamplingThread : public base::Thread {
static std::vector<MemoryRange> DoSynchronousSample(v8::Isolate* isolate) {
MemoryRange code_pages_copy[kBufSize];
size_t num_pages = isolate->CopyCodePages(kBufSize, code_pages_copy);
DCHECK_LE(num_pages, kBufSize);
EXPECT_LE(num_pages, kBufSize);
return std::vector<MemoryRange>{code_pages_copy,
&code_pages_copy[num_pages]};
}
@ -389,19 +380,16 @@ class SamplingThread : public base::Thread {
MemoryRange code_pages_copy_[kBufSize];
};
TEST(LargeCodeObjectWithSignalHandler) {
TEST_F(CodePagesTest, LargeCodeObjectWithSignalHandler) {
// We don't want incremental marking to start which could cause the code to
// not be collected on the CollectGarbage() call.
ManualGCScope manual_gc_scope;
ManualGCScope manual_gc_scope(i_isolate());
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
if (!i_isolate->RequiresCodeRange() && !kHaveCodePages) return;
if (!i_isolate()->RequiresCodeRange() && !kHaveCodePages) return;
// Create a big function that ends up in CODE_LO_SPACE.
const int instruction_size = Page::kPageSize + 1;
CHECK_GT(instruction_size, MemoryChunkLayout::MaxRegularCodeObjectSize());
EXPECT_GT(instruction_size, MemoryChunkLayout::MaxRegularCodeObjectSize());
std::unique_ptr<byte[]> instructions(new byte[instruction_size]);
CodeDesc desc;
@ -416,21 +404,22 @@ TEST(LargeCodeObjectWithSignalHandler) {
Address stale_code_address;
SignalSender signal_sender(isolate);
SignalSender signal_sender(isolate());
signal_sender.Start();
// Take an initial sample.
std::vector<MemoryRange> initial_pages =
SamplingThread::DoSynchronousSample(isolate);
SamplingThread::DoSynchronousSample(isolate());
SamplingThread sampling_thread(&signal_sender);
sampling_thread.StartSynchronously();
{
HandleScope scope(i_isolate);
HandleScope scope(i_isolate());
Handle<Code> foo_code =
Factory::CodeBuilder(i_isolate, desc, CodeKind::WASM_FUNCTION).Build();
Factory::CodeBuilder(i_isolate(), desc, CodeKind::WASM_FUNCTION)
.Build();
CHECK(i_isolate->heap()->InSpace(*foo_code, CODE_LO_SPACE));
EXPECT_TRUE(i_isolate()->heap()->InSpace(*foo_code, CODE_LO_SPACE));
// Do a synchronous sample to ensure that we capture the state with the
// extra code page.
@ -439,11 +428,11 @@ TEST(LargeCodeObjectWithSignalHandler) {
// Check that the page was added.
std::vector<MemoryRange> pages =
SamplingThread::DoSynchronousSample(isolate);
if (i_isolate->RequiresCodeRange()) {
CHECK(PagesContainsAddress(&pages, foo_code->address()));
SamplingThread::DoSynchronousSample(isolate());
if (i_isolate()->RequiresCodeRange()) {
EXPECT_TRUE(PagesContainsAddress(&pages, foo_code->address()));
} else {
CHECK(PagesHasExactPage(&pages, foo_code->address()));
EXPECT_TRUE(PagesHasExactPage(&pages, foo_code->address()));
}
stale_code_address = foo_code->address();
@ -453,31 +442,30 @@ TEST(LargeCodeObjectWithSignalHandler) {
sampling_thread.StartSynchronously();
// Delete the large code object.
CcTest::CollectGarbage(CODE_LO_SPACE);
CHECK(!i_isolate->heap()->InSpaceSlow(stale_code_address, CODE_LO_SPACE));
CollectGarbage(CODE_LO_SPACE);
EXPECT_TRUE(
!i_isolate()->heap()->InSpaceSlow(stale_code_address, CODE_LO_SPACE));
sampling_thread.Stop();
sampling_thread.Join();
std::vector<MemoryRange> pages = SamplingThread::DoSynchronousSample(isolate);
CHECK(!PagesHasExactPage(&pages, stale_code_address));
std::vector<MemoryRange> pages =
SamplingThread::DoSynchronousSample(isolate());
EXPECT_TRUE(!PagesHasExactPage(&pages, stale_code_address));
signal_sender.Stop();
}
TEST(Sorted) {
TEST_F(CodePagesTest, Sorted) {
// We don't want incremental marking to start which could cause the code to
// not be collected on the CollectGarbage() call.
ManualGCScope manual_gc_scope;
ManualGCScope manual_gc_scope(i_isolate());
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
if (!i_isolate->RequiresCodeRange() && !kHaveCodePages) return;
if (!i_isolate()->RequiresCodeRange() && !kHaveCodePages) return;
// Create a big function that ends up in CODE_LO_SPACE.
const int instruction_size = Page::kPageSize + 1;
CHECK_GT(instruction_size, MemoryChunkLayout::MaxRegularCodeObjectSize());
EXPECT_GT(instruction_size, MemoryChunkLayout::MaxRegularCodeObjectSize());
std::unique_ptr<byte[]> instructions(new byte[instruction_size]);
CodeDesc desc;
@ -492,69 +480,77 @@ TEST(Sorted) {
// Take an initial sample.
std::vector<MemoryRange> initial_pages =
SamplingThread::DoSynchronousSample(isolate);
SamplingThread::DoSynchronousSample(isolate());
size_t initial_num_pages = initial_pages.size();
auto compare = [](const MemoryRange& a, const MemoryRange& b) {
return a.start < b.start;
};
{
HandleScope outer_scope(i_isolate);
HandleScope outer_scope(i_isolate());
Handle<Code> code1, code3;
Address code2_address;
code1 =
Factory::CodeBuilder(i_isolate, desc, CodeKind::WASM_FUNCTION).Build();
CHECK(i_isolate->heap()->InSpace(*code1, CODE_LO_SPACE));
code1 = Factory::CodeBuilder(i_isolate(), desc, CodeKind::WASM_FUNCTION)
.Build();
EXPECT_TRUE(i_isolate()->heap()->InSpace(*code1, CODE_LO_SPACE));
{
HandleScope scope(i_isolate);
HandleScope scope(i_isolate());
// Create three large code objects, we'll delete the middle one and check
// everything is still sorted.
Handle<Code> code2 =
Factory::CodeBuilder(i_isolate, desc, CodeKind::WASM_FUNCTION)
Factory::CodeBuilder(i_isolate(), desc, CodeKind::WASM_FUNCTION)
.Build();
CHECK(i_isolate->heap()->InSpace(*code2, CODE_LO_SPACE));
code3 = Factory::CodeBuilder(i_isolate, desc, CodeKind::WASM_FUNCTION)
EXPECT_TRUE(i_isolate()->heap()->InSpace(*code2, CODE_LO_SPACE));
code3 = Factory::CodeBuilder(i_isolate(), desc, CodeKind::WASM_FUNCTION)
.Build();
CHECK(i_isolate->heap()->InSpace(*code3, CODE_LO_SPACE));
EXPECT_TRUE(i_isolate()->heap()->InSpace(*code3, CODE_LO_SPACE));
code2_address = code2->address();
CHECK(i_isolate->heap()->InSpaceSlow(code1->address(), CODE_LO_SPACE));
CHECK(i_isolate->heap()->InSpaceSlow(code2->address(), CODE_LO_SPACE));
CHECK(i_isolate->heap()->InSpaceSlow(code3->address(), CODE_LO_SPACE));
EXPECT_TRUE(
i_isolate()->heap()->InSpaceSlow(code1->address(), CODE_LO_SPACE));
EXPECT_TRUE(
i_isolate()->heap()->InSpaceSlow(code2->address(), CODE_LO_SPACE));
EXPECT_TRUE(
i_isolate()->heap()->InSpaceSlow(code3->address(), CODE_LO_SPACE));
// Check that the pages were added.
std::vector<MemoryRange> pages =
SamplingThread::DoSynchronousSample(isolate);
if (i_isolate->RequiresCodeRange()) {
CHECK_EQ(pages.size(), initial_num_pages);
SamplingThread::DoSynchronousSample(isolate());
if (i_isolate()->RequiresCodeRange()) {
EXPECT_EQ(pages.size(), initial_num_pages);
} else {
CHECK_EQ(pages.size(), initial_num_pages + 3);
EXPECT_EQ(pages.size(), initial_num_pages + 3);
}
CHECK(std::is_sorted(pages.begin(), pages.end(), compare));
EXPECT_TRUE(std::is_sorted(pages.begin(), pages.end(), compare));
code3 = scope.CloseAndEscape(code3);
}
CHECK(i_isolate->heap()->InSpaceSlow(code1->address(), CODE_LO_SPACE));
CHECK(i_isolate->heap()->InSpaceSlow(code2_address, CODE_LO_SPACE));
CHECK(i_isolate->heap()->InSpaceSlow(code3->address(), CODE_LO_SPACE));
EXPECT_TRUE(
i_isolate()->heap()->InSpaceSlow(code1->address(), CODE_LO_SPACE));
EXPECT_TRUE(i_isolate()->heap()->InSpaceSlow(code2_address, CODE_LO_SPACE));
EXPECT_TRUE(
i_isolate()->heap()->InSpaceSlow(code3->address(), CODE_LO_SPACE));
// Delete code2.
CcTest::CollectGarbage(CODE_LO_SPACE);
CHECK(i_isolate->heap()->InSpaceSlow(code1->address(), CODE_LO_SPACE));
CHECK(!i_isolate->heap()->InSpaceSlow(code2_address, CODE_LO_SPACE));
CHECK(i_isolate->heap()->InSpaceSlow(code3->address(), CODE_LO_SPACE));
CollectGarbage(CODE_LO_SPACE);
EXPECT_TRUE(
i_isolate()->heap()->InSpaceSlow(code1->address(), CODE_LO_SPACE));
EXPECT_TRUE(
!i_isolate()->heap()->InSpaceSlow(code2_address, CODE_LO_SPACE));
EXPECT_TRUE(
i_isolate()->heap()->InSpaceSlow(code3->address(), CODE_LO_SPACE));
std::vector<MemoryRange> pages =
SamplingThread::DoSynchronousSample(isolate);
if (i_isolate->RequiresCodeRange()) {
CHECK_EQ(pages.size(), initial_num_pages);
SamplingThread::DoSynchronousSample(isolate());
if (i_isolate()->RequiresCodeRange()) {
EXPECT_EQ(pages.size(), initial_num_pages);
} else {
CHECK_EQ(pages.size(), initial_num_pages + 2);
EXPECT_EQ(pages.size(), initial_num_pages + 2);
}
CHECK(std::is_sorted(pages.begin(), pages.end(), compare));
EXPECT_TRUE(std::is_sorted(pages.begin(), pages.end(), compare));
}
}