1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
#include "WAVM/Platform/VectorOverMMap.h"
#include <limits.h>
#include <unistd.h>
#include <algorithm>
#include <cerrno>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <iostream>
#include "WAVM/Inline/Assert.h"
using namespace WAVM;
using namespace WAVM::Runtime;
VectorOverMMap::VectorOverMMap()
: committedPageCount(0), capacityPageCount(2), data(allocateAndProtect(0, 2))
{
}
VectorOverMMap::~VectorOverMMap()
{
int err = ::munmap(data, (capacityPageCount + guardPageCount) * pageSize);
if(err < 0) { checkForOOM("Failed to unmap VectorOverMMap; terminating"); }
}
void VectorOverMMap::grow(size_t morePages)
{
if(capacityPageCount < committedPageCount + morePages)
{
resizeWithDoubling(morePages);
return;
}
int err = ::mprotect(static_cast<uint8_t*>(data) + (committedPageCount * pageSize),
morePages * pageSize,
PROT_READ | PROT_WRITE);
if(err < 0) { checkForOOM("Failed to protect VectorOverMMap; terminating"); }
committedPageCount += morePages;
};
size_t VectorOverMMap::getNumReservedBytes() const { return committedPageCount * pageSize; }
void* VectorOverMMap::getData() const { return data; }
void VectorOverMMap::resizeWithDoubling(size_t morePages)
{
auto oldCommitted = committedPageCount;
auto newCommitted = oldCommitted + morePages;
auto oldCapacity = capacityPageCount;
auto newCapacity = std::max(oldCapacity * 2, newCommitted * 2);
auto oldData = data;
auto newData = allocateAndProtect(newCommitted, newCapacity);
::memcpy(newData, oldData, oldCommitted * pageSize);
committedPageCount = newCommitted;
capacityPageCount = newCapacity;
data = newData;
int err = ::munmap(oldData, (oldCapacity + guardPageCount) * pageSize);
if(err < 0) { checkForOOM("Failed to unmap VectorOverMMap; terminating"); }
}
void* VectorOverMMap::allocateAndProtect(size_t committed, size_t capacity)
{
WAVM_ASSERT(committed <= capacity);
auto allocated
= ::mmap(nullptr, (capacity + guardPageCount) * pageSize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if(!allocated) { checkForOOM("Failed to allocate VectorOverMMap; terminating"); }
int err = ::mprotect(allocated, committed * pageSize, PROT_READ | PROT_WRITE);
if(err < 0) { checkForOOM("Failed to protect VectorOverMMap; terminating"); }
return allocated;
}
void VectorOverMMap::checkForOOM(const char* message)
{
if(errno == ENOMEM)
{
fprintf(stderr,
"Out-of-memory condition detected while allocating VectorOverMMap; terminating\n");
_exit(9);
}
fprintf(stderr, "%s\n", message);
_exit(9);
}
|