summaryrefslogtreecommitdiffstats
path: root/contrib/restricted/wavm/Lib/Runtime/VectorOverMMap.cpp
blob: 060373cac2b63cbbeb137eba02cb5831e99f7791 (plain) (blame)
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);
}