f29628fe63
Moving these constants from global namespace to Page class prevents possible conflicts with other kPageSize/kPageMask/kBlockSize constants and allows us to export value of Page::kPageMask constant into runtime offsets via runtime/vm/compiler/runtime_offsets_list.h. TEST=ci Change-Id: I4357f4644f0f5f7beba50184231fef55dd86b124 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/476147 Reviewed-by: Ryan Macnak <rmacnak@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
131 lines
4.1 KiB
C++
131 lines
4.1 KiB
C++
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "vm/virtual_memory.h"
|
|
#include "platform/assert.h"
|
|
#include "vm/heap/heap.h"
|
|
#include "vm/unit_test.h"
|
|
#include "vm/virtual_memory_compressed.h"
|
|
|
|
namespace dart {
|
|
|
|
bool IsZero(char* begin, char* end) {
|
|
for (char* current = begin; current < end; ++current) {
|
|
if (*current != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
VM_UNIT_TEST_CASE(AllocateVirtualMemory) {
|
|
const intptr_t kVirtualMemoryBlockSize = 64 * KB;
|
|
VirtualMemory* vm =
|
|
VirtualMemory::Allocate(kVirtualMemoryBlockSize, false, false, "test");
|
|
EXPECT(vm != nullptr);
|
|
EXPECT(vm->address() != nullptr);
|
|
EXPECT_EQ(vm->start(), reinterpret_cast<uword>(vm->address()));
|
|
EXPECT_EQ(kVirtualMemoryBlockSize, vm->size());
|
|
EXPECT_EQ(vm->start() + kVirtualMemoryBlockSize, vm->end());
|
|
EXPECT(vm->Contains(vm->start()));
|
|
EXPECT(vm->Contains(vm->start() + 1));
|
|
EXPECT(vm->Contains(vm->start() + kVirtualMemoryBlockSize - 1));
|
|
EXPECT(vm->Contains(vm->start() + (kVirtualMemoryBlockSize / 2)));
|
|
EXPECT(!vm->Contains(vm->start() - 1));
|
|
EXPECT(!vm->Contains(vm->end()));
|
|
EXPECT(!vm->Contains(vm->end() + 1));
|
|
EXPECT(!vm->Contains(0));
|
|
EXPECT(!vm->Contains(static_cast<uword>(-1)));
|
|
|
|
char* buf = reinterpret_cast<char*>(vm->address());
|
|
EXPECT(IsZero(buf, buf + vm->size()));
|
|
buf[0] = 'a';
|
|
buf[1] = 'c';
|
|
buf[2] = '/';
|
|
buf[3] = 'd';
|
|
buf[4] = 'c';
|
|
buf[5] = 0;
|
|
EXPECT_STREQ("ac/dc", buf);
|
|
|
|
delete vm;
|
|
}
|
|
|
|
VM_UNIT_TEST_CASE(AllocateAlignedVirtualMemory) {
|
|
intptr_t kHeapPageSize = Page::kPageSize;
|
|
intptr_t kVirtualPageSize = 4096;
|
|
|
|
intptr_t kIterations = kHeapPageSize / kVirtualPageSize;
|
|
for (intptr_t i = 0; i < kIterations; i++) {
|
|
VirtualMemory* vm = VirtualMemory::AllocateAligned(
|
|
kHeapPageSize, kHeapPageSize, false, false, "test");
|
|
EXPECT(Utils::IsAligned(vm->start(), kHeapPageSize));
|
|
EXPECT_EQ(kHeapPageSize, vm->size());
|
|
delete vm;
|
|
}
|
|
}
|
|
|
|
VM_UNIT_TEST_CASE(FreeVirtualMemory) {
|
|
// Reservations should always be handed back to OS upon destruction.
|
|
const intptr_t kVirtualMemoryBlockSize = 10 * MB;
|
|
const intptr_t kIterations = 900; // Enough to exhaust 32-bit address space.
|
|
for (intptr_t i = 0; i < kIterations; ++i) {
|
|
VirtualMemory* vm =
|
|
VirtualMemory::Allocate(kVirtualMemoryBlockSize, false, false, "test");
|
|
delete vm;
|
|
}
|
|
// Check that truncation does not introduce leaks.
|
|
for (intptr_t i = 0; i < kIterations; ++i) {
|
|
VirtualMemory* vm =
|
|
VirtualMemory::Allocate(kVirtualMemoryBlockSize, false, false, "test");
|
|
vm->Truncate(kVirtualMemoryBlockSize / 2);
|
|
delete vm;
|
|
}
|
|
for (intptr_t i = 0; i < kIterations; ++i) {
|
|
VirtualMemory* vm =
|
|
VirtualMemory::Allocate(kVirtualMemoryBlockSize, true, false, "test");
|
|
vm->Truncate(0);
|
|
delete vm;
|
|
}
|
|
}
|
|
|
|
#if defined(DART_HOST_OS_MACOS)
|
|
// TODO(https://dartbug.com/52579): Reenable on Fuchsia.
|
|
|
|
static int testFunction(int x) {
|
|
return x * 2;
|
|
}
|
|
|
|
NO_SANITIZE_UNDEFINED_FUNCTION // See https://dartbug.com/52440
|
|
VM_UNIT_TEST_CASE(DuplicateRXVirtualMemory) {
|
|
const uword page_size = VirtualMemory::PageSize();
|
|
const uword pointer = reinterpret_cast<uword>(&testFunction);
|
|
const uword page_start = Utils::RoundDown(pointer, page_size);
|
|
const uword offset = pointer - page_start;
|
|
|
|
// Grab 2 * page_size, in case testFunction happens to land near the end of
|
|
// the page.
|
|
VirtualMemory* vm = VirtualMemory::ForImagePage(
|
|
reinterpret_cast<void*>(page_start), 2 * page_size);
|
|
EXPECT_NE(nullptr, vm);
|
|
|
|
const bool is_executable = false;
|
|
VirtualMemory* vm2 = VirtualMemory::AllocateAligned(
|
|
vm->size(), Page::kPageSize, is_executable,
|
|
/*is_compressed=*/false, "FfiCallbackMetadata::TrampolinePage");
|
|
bool ok = vm->DuplicateRX(vm2);
|
|
EXPECT_EQ(true, ok);
|
|
|
|
auto testFunction2 = reinterpret_cast<int (*)(int)>(vm2->start() + offset);
|
|
EXPECT_NE(&testFunction, testFunction2);
|
|
|
|
EXPECT_EQ(246, testFunction2(123));
|
|
|
|
delete vm;
|
|
delete vm2;
|
|
}
|
|
|
|
#endif // defined(DART_HOST_OS_MACOS)
|
|
|
|
} // namespace dart
|