1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/globals.h"
6#if defined(HOST_OS_WINDOWS)
7
8#include "vm/virtual_memory.h"
9
10#include "platform/assert.h"
11#include "vm/os.h"
12
13#include "vm/isolate.h"
14
15namespace dart {
16
17DECLARE_FLAG(bool, write_protect_code);
18
19uword VirtualMemory::page_size_ = 0;
20
21intptr_t VirtualMemory::CalculatePageSize() {
22 SYSTEM_INFO info;
23 GetSystemInfo(&info);
24 const intptr_t page_size = info.dwPageSize;
25 ASSERT(page_size != 0);
26 ASSERT(Utils::IsPowerOfTwo(page_size));
27 return page_size;
28}
29
30void VirtualMemory::Init() {
31 page_size_ = CalculatePageSize();
32}
33
34bool VirtualMemory::DualMappingEnabled() {
35 return false;
36}
37
38VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
39 intptr_t alignment,
40 bool is_executable,
41 const char* name) {
42 // When FLAG_write_protect_code is active, code memory (indicated by
43 // is_executable = true) is allocated as non-executable and later
44 // changed to executable via VirtualMemory::Protect.
45 ASSERT(Utils::IsAligned(size, PageSize()));
46 ASSERT(Utils::IsPowerOfTwo(alignment));
47 ASSERT(Utils::IsAligned(alignment, PageSize()));
48 intptr_t reserved_size = size + alignment - PageSize();
49 int prot = (is_executable && !FLAG_write_protect_code)
50 ? PAGE_EXECUTE_READWRITE
51 : PAGE_READWRITE;
52 void* address = VirtualAlloc(NULL, reserved_size, MEM_RESERVE, prot);
53 if (address == NULL) {
54 return NULL;
55 }
56
57 void* aligned_address = reinterpret_cast<void*>(
58 Utils::RoundUp(reinterpret_cast<uword>(address), alignment));
59 if (VirtualAlloc(aligned_address, size, MEM_COMMIT, prot) !=
60 aligned_address) {
61 VirtualFree(address, reserved_size, MEM_RELEASE);
62 return NULL;
63 }
64
65 MemoryRegion region(aligned_address, size);
66 MemoryRegion reserved(address, reserved_size);
67 return new VirtualMemory(region, reserved);
68}
69
70VirtualMemory::~VirtualMemory() {
71 // Note that the size of the reserved region might be set to 0 by
72 // Truncate(0, true) but that does not actually release the mapping
73 // itself. The only way to release the mapping is to invoke VirtualFree
74 // with original base pointer and MEM_RELEASE.
75 if (!vm_owns_region()) {
76 return;
77 }
78 if (VirtualFree(reserved_.pointer(), 0, MEM_RELEASE) == 0) {
79 FATAL1("VirtualFree failed: Error code %d\n", GetLastError());
80 }
81}
82
83void VirtualMemory::FreeSubSegment(void* address,
84 intptr_t size) {
85 if (VirtualFree(address, size, MEM_DECOMMIT) == 0) {
86 FATAL1("VirtualFree failed: Error code %d\n", GetLastError());
87 }
88}
89
90void VirtualMemory::Protect(void* address, intptr_t size, Protection mode) {
91#if defined(DEBUG)
92 Thread* thread = Thread::Current();
93 ASSERT(thread == nullptr || thread->IsMutatorThread() ||
94 thread->isolate() == nullptr ||
95 thread->isolate()->mutator_thread()->IsAtSafepoint());
96#endif
97 uword start_address = reinterpret_cast<uword>(address);
98 uword end_address = start_address + size;
99 uword page_address = Utils::RoundDown(start_address, PageSize());
100 DWORD prot = 0;
101 switch (mode) {
102 case kNoAccess:
103 prot = PAGE_NOACCESS;
104 break;
105 case kReadOnly:
106 prot = PAGE_READONLY;
107 break;
108 case kReadWrite:
109 prot = PAGE_READWRITE;
110 break;
111 case kReadExecute:
112 prot = PAGE_EXECUTE_READ;
113 break;
114 case kReadWriteExecute:
115 prot = PAGE_EXECUTE_READWRITE;
116 break;
117 }
118 DWORD old_prot = 0;
119 if (VirtualProtect(reinterpret_cast<void*>(page_address),
120 end_address - page_address, prot, &old_prot) == 0) {
121 FATAL1("VirtualProtect failed %d\n", GetLastError());
122 }
123}
124
125} // namespace dart
126
127#endif // defined(HOST_OS_WINDOWS)
128