dart-sdk/runtime/vm/virtual_memory_test.cc
koda@google.com 0b85873fc8 Deletion barrier preparation: validate overwritten references.
With the upcoming deletion barrier, every update of a pointer field must know whether the previous value was a valid pointer.

Currently, we always use StorePointer/StoreSmi, both for initialization and updates.

Initialization, and thus the potential for overwriting garbage values, appears in three places:
1. Object::Allocate/Foo::New.
2. Creating isolate from full snapshot.
3. Allocation in generated code.

Case 1 already null-initializes all underlying memory.
Case 2 is addressed by this CL by exploiting that:
i) fresh pages are zero-filled by OS, and
ii) freelist headers use only even values.
Case 3 is remains a TODO for future CLs.

(An alternative solution for case 2 would have been to add an init_foo method for every set_foo called.)

R=iposva@google.com

Review URL: https://codereview.chromium.org//792163003

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@42584 260f80e4-7a28-3924-810f-c04153c831b5
2015-01-02 18:16:13 +00:00

111 lines
3.3 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 "platform/assert.h"
#include "vm/unit_test.h"
#include "vm/virtual_memory.h"
namespace dart {
bool IsZero(char* begin, char* end) {
for (char* current = begin; current < end; ++current) {
if (*current != 0) {
return false;
}
}
return true;
}
UNIT_TEST_CASE(AllocateVirtualMemory) {
const intptr_t kVirtualMemoryBlockSize = 64 * KB;
VirtualMemory* vm = VirtualMemory::Reserve(kVirtualMemoryBlockSize);
EXPECT(vm != NULL);
EXPECT(vm->address() != NULL);
EXPECT_EQ(kVirtualMemoryBlockSize, vm->size());
EXPECT_EQ(vm->start(), reinterpret_cast<uword>(vm->address()));
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)));
vm->Commit(false);
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;
}
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::Reserve(kVirtualMemoryBlockSize);
vm->Commit(false);
delete vm;
}
// Check that truncation does not introduce leaks.
for (intptr_t i = 0; i < kIterations; ++i) {
VirtualMemory* vm = VirtualMemory::Reserve(kVirtualMemoryBlockSize);
vm->Commit(false);
vm->Truncate(kVirtualMemoryBlockSize / 2, true);
delete vm;
}
for (intptr_t i = 0; i < kIterations; ++i) {
VirtualMemory* vm = VirtualMemory::Reserve(kVirtualMemoryBlockSize);
vm->Commit(true);
vm->Truncate(kVirtualMemoryBlockSize / 2, false);
delete vm;
}
for (intptr_t i = 0; i < kIterations; ++i) {
VirtualMemory* vm = VirtualMemory::Reserve(kVirtualMemoryBlockSize);
vm->Commit(true);
vm->Truncate(0, true);
delete vm;
}
for (intptr_t i = 0; i < kIterations; ++i) {
VirtualMemory* vm = VirtualMemory::Reserve(kVirtualMemoryBlockSize);
vm->Commit(false);
vm->Truncate(0, false);
delete vm;
}
}
UNIT_TEST_CASE(VirtualMemoryCommitPartial) {
const intptr_t kVirtualMemoryBlockSize = 3 * MB;
VirtualMemory* vm = VirtualMemory::Reserve(kVirtualMemoryBlockSize);
EXPECT(vm != NULL);
// Commit only the middle MB and write to it.
const uword commit_start = vm->start() + (1 * MB);
const intptr_t kCommitSize = 1 * MB;
vm->Commit(commit_start, kCommitSize, false);
char* buf = reinterpret_cast<char*>(commit_start);
EXPECT(IsZero(buf, buf + kCommitSize));
buf[0] = 'f';
buf[1] = 'o';
buf[2] = 'o';
buf[3] = 0;
EXPECT_STREQ("foo", buf);
delete vm;
}
} // namespace dart