Skip to content

Commit 4899bcb

Browse files
Bill BudgeCommit Bot
authored andcommitted
Reland "[Memory] Use OS::Allocate for all OS memory allocations."
This is a reland of 7e78506 Original change's description: > [Memory] Use OS::Allocate for all OS memory allocations. > > - Eliminates OS::ReserveRegion and OS::ReserveAlignedRegion. > - Changes OS::Allocate to take alignment parameter, reorders parameters > to match page_allocator. > - Since the size of memory allocation can be deduced, don't return the > amount of memory allocated. > - Changes reservation of aligned address space. Before we would reserve > (size + alignment) rounded up to page size. This is too much, because > maximum misalignment is (alignment - page_size). > - On Windows and Cygwin, we release an oversize allocation and > immediately retry at the aligned address in the allocation. If we > lose the address due to a race, we just retry. > - Clean up all the calls to OS::Allocate in codegen and tests by adding > helper AllocateSystemPage function (allocation.h) and > AllocateAssemblerBuffer (cctest.h). > - Changes 'assm' to 'masm' in some targets for consistency when using > a macro-assembler. > > Bug: chromium:756050 > Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng > Change-Id: I306dbe042cc867670fdc935abca29db074b0da71 > Reviewed-on: https://chromium-review.googlesource.com/749848 > Commit-Queue: Bill Budge <bbudge@chromium.org> > Reviewed-by: Michael Lippautz <mlippautz@chromium.org> > Reviewed-by: Hannes Payer <hpayer@chromium.org> > Cr-Commit-Position: refs/heads/master@{#49235} Bug: chromium:756050 Change-Id: I333f7a6aea0bcb608d01cafb43e94893a4625b15 Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng Reviewed-on: https://chromium-review.googlesource.com/758509 Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Commit-Queue: Bill Budge <bbudge@chromium.org> Cr-Commit-Position: refs/heads/master@{#49273}
1 parent a99f0ce commit 4899bcb

30 files changed

Lines changed: 536 additions & 603 deletions

src/allocation.cc

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -103,21 +103,28 @@ void AlignedFree(void *ptr) {
103103
#endif
104104
}
105105

106-
VirtualMemory::VirtualMemory() : address_(nullptr), size_(0) {}
107-
108-
VirtualMemory::VirtualMemory(size_t size, void* hint)
109-
: address_(base::OS::ReserveRegion(size, hint)), size_(size) {
110-
#if defined(LEAK_SANITIZER)
111-
__lsan_register_root_region(address_, size_);
112-
#endif
106+
byte* AllocateSystemPage(void* address, size_t* allocated) {
107+
size_t page_size = base::OS::AllocatePageSize();
108+
void* result = base::OS::Allocate(address, page_size, page_size,
109+
base::OS::MemoryPermission::kReadWrite);
110+
if (result != nullptr) *allocated = page_size;
111+
return static_cast<byte*>(result);
113112
}
114113

115-
VirtualMemory::VirtualMemory(size_t size, size_t alignment, void* hint)
114+
VirtualMemory::VirtualMemory() : address_(nullptr), size_(0) {}
115+
116+
VirtualMemory::VirtualMemory(size_t size, void* hint, size_t alignment)
116117
: address_(nullptr), size_(0) {
117-
address_ = base::OS::ReserveAlignedRegion(size, alignment, hint, &size_);
118+
size_t page_size = base::OS::AllocatePageSize();
119+
size_t alloc_size = RoundUp(size, page_size);
120+
address_ = base::OS::Allocate(hint, alloc_size, alignment,
121+
base::OS::MemoryPermission::kNoAccess);
122+
if (address_ != nullptr) {
123+
size_ = alloc_size;
118124
#if defined(LEAK_SANITIZER)
119-
__lsan_register_root_region(address_, size_);
125+
__lsan_register_root_region(address_, size_);
120126
#endif
127+
}
121128
}
122129

123130
VirtualMemory::~VirtualMemory() {
@@ -205,14 +212,14 @@ bool AllocVirtualMemory(size_t size, void* hint, VirtualMemory* result) {
205212

206213
bool AlignedAllocVirtualMemory(size_t size, size_t alignment, void* hint,
207214
VirtualMemory* result) {
208-
VirtualMemory first_try(size, alignment, hint);
215+
VirtualMemory first_try(size, hint, alignment);
209216
if (first_try.IsReserved()) {
210217
result->TakeControl(&first_try);
211218
return true;
212219
}
213220

214221
V8::GetCurrentPlatform()->OnCriticalMemoryPressure();
215-
VirtualMemory second_try(size, alignment, hint);
222+
VirtualMemory second_try(size, hint, alignment);
216223
result->TakeControl(&second_try);
217224
return result->IsReserved();
218225
}

src/allocation.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,19 +76,22 @@ class FreeStoreAllocationPolicy {
7676
void* AlignedAlloc(size_t size, size_t alignment);
7777
void AlignedFree(void *ptr);
7878

79+
// Allocates a single system memory page with read/write permissions. The
80+
// address parameter is a hint. Returns the base address of the memory, or null
81+
// on failure. Permissions can be changed on the base address.
82+
byte* AllocateSystemPage(void* address, size_t* allocated);
83+
7984
// Represents and controls an area of reserved memory.
8085
class V8_EXPORT_PRIVATE VirtualMemory {
8186
public:
8287
// Empty VirtualMemory object, controlling no reserved memory.
8388
VirtualMemory();
8489

85-
// Reserves virtual memory with size.
86-
explicit VirtualMemory(size_t size, void* hint);
87-
88-
// Reserves virtual memory containing an area of the given size that
89-
// is aligned per alignment. This may not be at the position returned
90-
// by address().
91-
VirtualMemory(size_t size, size_t alignment, void* hint);
90+
// Reserves virtual memory containing an area of the given size that is
91+
// aligned per alignment. This may not be at the position returned by
92+
// address().
93+
VirtualMemory(size_t size, void* hint,
94+
size_t alignment = base::OS::AllocatePageSize());
9295

9396
// Construct a virtual memory by assigning it some already mapped address
9497
// and size.

src/api.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,10 +489,15 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
489489
virtual void Free(void* data, size_t) { free(data); }
490490

491491
virtual void* Reserve(size_t length) {
492+
size_t page_size = base::OS::AllocatePageSize();
493+
size_t allocated = RoundUp(length, page_size);
492494
void* address =
493-
base::OS::ReserveRegion(length, base::OS::GetRandomMmapAddr());
495+
base::OS::Allocate(base::OS::GetRandomMmapAddr(), allocated, page_size,
496+
base::OS::MemoryPermission::kNoAccess);
494497
#if defined(LEAK_SANITIZER)
495-
__lsan_register_root_region(address, length);
498+
if (address != nullptr) {
499+
__lsan_register_root_region(address, allocated);
500+
}
496501
#endif
497502
return address;
498503
}

src/arm/codegen-arm.cc

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@
1414
namespace v8 {
1515
namespace internal {
1616

17-
1817
#define __ masm.
1918

2019
#if defined(V8_HOST_ARCH_ARM)
20+
2121
MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
2222
MemCopyUint8Function stub) {
2323
#if defined(USE_SIMULATOR)
2424
return stub;
2525
#else
26-
size_t actual_size;
27-
byte* buffer = static_cast<byte*>(base::OS::Allocate(
28-
1 * KB, &actual_size, base::OS::MemoryPermission::kReadWriteExecute));
26+
size_t allocated = 0;
27+
byte* buffer =
28+
AllocateSystemPage(isolate->heap()->GetRandomMmapAddr(), &allocated);
2929
if (buffer == nullptr) return stub;
3030

31-
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
31+
MacroAssembler masm(isolate, buffer, static_cast<int>(allocated),
3232
CodeObjectRequired::kNo);
3333

3434
Register dest = r0;
@@ -169,8 +169,8 @@ MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
169169
masm.GetCode(isolate, &desc);
170170
DCHECK(!RelocInfo::RequiresRelocation(isolate, desc));
171171

172-
Assembler::FlushICache(isolate, buffer, actual_size);
173-
base::OS::SetReadAndExecutable(buffer, actual_size);
172+
Assembler::FlushICache(isolate, buffer, allocated);
173+
base::OS::SetReadAndExecutable(buffer, allocated);
174174
return FUNCTION_CAST<MemCopyUint8Function>(buffer);
175175
#endif
176176
}
@@ -182,12 +182,12 @@ MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function(
182182
#if defined(USE_SIMULATOR)
183183
return stub;
184184
#else
185-
size_t actual_size;
186-
byte* buffer = static_cast<byte*>(base::OS::Allocate(
187-
1 * KB, &actual_size, base::OS::MemoryPermission::kReadWriteExecute));
185+
size_t allocated = 0;
186+
byte* buffer =
187+
AllocateSystemPage(isolate->heap()->GetRandomMmapAddr(), &allocated);
188188
if (buffer == nullptr) return stub;
189189

190-
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
190+
MacroAssembler masm(isolate, buffer, static_cast<int>(allocated),
191191
CodeObjectRequired::kNo);
192192

193193
Register dest = r0;
@@ -259,8 +259,8 @@ MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function(
259259
CodeDesc desc;
260260
masm.GetCode(isolate, &desc);
261261

262-
Assembler::FlushICache(isolate, buffer, actual_size);
263-
base::OS::SetReadAndExecutable(buffer, actual_size);
262+
Assembler::FlushICache(isolate, buffer, allocated);
263+
base::OS::SetReadAndExecutable(buffer, allocated);
264264

265265
return FUNCTION_CAST<MemCopyUint16Uint8Function>(buffer);
266266
#endif
@@ -271,12 +271,12 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
271271
#if defined(USE_SIMULATOR)
272272
return nullptr;
273273
#else
274-
size_t actual_size;
275-
byte* buffer = static_cast<byte*>(base::OS::Allocate(
276-
1 * KB, &actual_size, base::OS::MemoryPermission::kReadWriteExecute));
274+
size_t allocated = 0;
275+
byte* buffer =
276+
AllocateSystemPage(isolate->heap()->GetRandomMmapAddr(), &allocated);
277277
if (buffer == nullptr) return nullptr;
278278

279-
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
279+
MacroAssembler masm(isolate, buffer, static_cast<int>(allocated),
280280
CodeObjectRequired::kNo);
281281

282282
__ MovFromFloatParameter(d0);
@@ -288,8 +288,8 @@ UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
288288
masm.GetCode(isolate, &desc);
289289
DCHECK(!RelocInfo::RequiresRelocation(isolate, desc));
290290

291-
Assembler::FlushICache(isolate, buffer, actual_size);
292-
base::OS::SetReadAndExecutable(buffer, actual_size);
291+
Assembler::FlushICache(isolate, buffer, allocated);
292+
base::OS::SetReadAndExecutable(buffer, allocated);
293293
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
294294
#endif
295295
}

src/base/platform/platform-cygwin.cc

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ namespace {
3434
// This causes VirtualMemory::Commit to not always commit the memory region
3535
// specified.
3636

37+
int GetProtectionFromMemoryPermission(OS::MemoryPermission access) {
38+
switch (access) {
39+
case OS::MemoryPermission::kNoAccess:
40+
return PAGE_NOACCESS;
41+
case OS::MemoryPermission::kReadWrite:
42+
return PAGE_READWRITE;
43+
case OS::MemoryPermission::kReadWriteExecute:
44+
return PAGE_EXECUTE_READWRITE;
45+
}
46+
UNREACHABLE();
47+
}
48+
3749
static void* RandomizedVirtualAlloc(size_t size, int action, int protection,
3850
void* hint) {
3951
LPVOID base = nullptr;
@@ -80,43 +92,44 @@ double CygwinTimezoneCache::LocalTimeOffset() {
8092
(loc->tm_isdst > 0 ? 3600 * msPerSecond : 0));
8193
}
8294

83-
// static
84-
void* OS::ReserveRegion(size_t size, void* hint) {
85-
return RandomizedVirtualAlloc(size, MEM_RESERVE, PAGE_NOACCESS, hint);
86-
}
87-
88-
// static
89-
void* OS::ReserveAlignedRegion(size_t size, size_t alignment, void* hint,
90-
size_t* allocated) {
91-
hint = AlignedAddress(hint, alignment);
92-
DCHECK_EQ(alignment % OS::AllocatePageSize(), 0);
93-
size_t request_size =
94-
RoundUp(size + alignment, static_cast<intptr_t>(OS::AllocatePageSize()));
95-
void* address = ReserveRegion(request_size, hint);
96-
if (address == nullptr) {
97-
*allocated = 0;
98-
return nullptr;
99-
}
100-
uint8_t* base = RoundUp(static_cast<uint8_t*>(address), alignment);
101-
// Try reducing the size by freeing and then reallocating a specific area.
102-
bool result = ReleaseRegion(address, request_size);
103-
USE(result);
104-
DCHECK(result);
105-
address = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
106-
if (address != nullptr) {
107-
request_size = size;
108-
DCHECK(base == static_cast<uint8_t*>(address));
109-
} else {
110-
// Resizing failed, just go with a bigger area.
111-
address = ReserveRegion(request_size, hint);
112-
if (address == nullptr) {
113-
*allocated = 0;
114-
return nullptr;
115-
}
95+
void* OS::Allocate(void* address, size_t size, size_t alignment,
96+
MemoryPermission access) {
97+
size_t page_size = AllocatePageSize();
98+
DCHECK_EQ(0, size % page_size);
99+
DCHECK_EQ(0, alignment % page_size);
100+
address = AlignedAddress(address, alignment);
101+
// Add the maximum misalignment so we are guaranteed an aligned base address.
102+
size_t request_size = size + (alignment - page_size);
103+
104+
int flags = (access == OS::MemoryPermission::kNoAccess)
105+
? MEM_RESERVE
106+
: MEM_RESERVE | MEM_COMMIT;
107+
int prot = GetProtectionFromMemoryPermission(access);
108+
109+
void* base = RandomizedVirtualAlloc(request_size, flags, prot, address);
110+
if (base == nullptr) return nullptr;
111+
112+
uint8_t* aligned_base = RoundUp(static_cast<uint8_t*>(base), alignment);
113+
int resize_attempts = 0;
114+
const int kMaxResizeAttempts = 3;
115+
while (aligned_base != base) {
116+
// Try reducing the size by freeing and then re-allocating at the aligned
117+
// base. Retry logic is needed since we may lose the memory due to a race.
118+
Free(base, request_size);
119+
if (resize_attempts == kMaxResizeAttempts) return nullptr;
120+
base = RandomizedVirtualAlloc(size, flags, prot, aligned_base);
121+
if (base == nullptr) return nullptr;
122+
aligned_base = RoundUp(static_cast<uint8_t*>(base), alignment);
123+
resize_attempts++;
116124
}
117125

118-
*allocated = request_size;
119-
return static_cast<void*>(address);
126+
return static_cast<void*>(aligned_base);
127+
}
128+
129+
void OS::Free(void* address, const size_t size) {
130+
// TODO(1240712): VirtualFree has a return value which is ignored here.
131+
VirtualFree(address, 0, MEM_RELEASE);
132+
USE(size);
120133
}
121134

122135
// static

src/base/platform/platform-fuchsia.cc

Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -18,42 +18,19 @@ TimezoneCache* OS::CreateTimezoneCache() {
1818
}
1919

2020
// static
21-
void* OS::Allocate(const size_t requested, size_t* allocated,
22-
OS::MemoryPermission access, void* hint) {
23-
CHECK(false); // TODO(scottmg): Port, https://crbug.com/731217.
24-
return nullptr;
25-
}
26-
27-
// static
28-
void OS::Guard(void* address, size_t size) {
29-
CHECK_EQ(ZX_OK, zx_vmar_protect(zx_vmar_root_self(),
30-
reinterpret_cast<uintptr_t>(address), size,
31-
0 /*no permissions*/));
32-
}
33-
34-
// static
35-
void* OS::ReserveRegion(size_t size, void* hint) {
36-
zx_handle_t vmo;
37-
if (zx_vmo_create(size, 0, &vmo) != ZX_OK) return nullptr;
38-
uintptr_t result;
39-
zx_status_t status = zx_vmar_map(zx_vmar_root_self(), 0, vmo, 0, size,
40-
0 /*no permissions*/, &result);
41-
zx_handle_close(vmo);
42-
if (status != ZX_OK) return nullptr;
43-
return reinterpret_cast<void*>(result);
44-
}
45-
46-
// static
47-
void* OS::ReserveAlignedRegion(size_t size, size_t alignment, void* hint,
48-
size_t* allocated) {
49-
DCHECK_EQ(alignment % OS::AllocatePageSize(), 0);
50-
hint = AlignedAddress(hint, alignment);
51-
size_t request_size =
52-
RoundUp(size + alignment, static_cast<intptr_t>(OS::AllocatePageSize()));
21+
void* OS::Allocate(void* address, size_t size, size_t alignment,
22+
OS::MemoryPermission access) {
23+
// Currently we only support reserving memory.
24+
DCHECK_EQ(MemoryPermission::kNoAccess, access);
25+
size_t page_size = OS::AllocatePageSize();
26+
DCHECK_EQ(0, size % page_size);
27+
DCHECK_EQ(0, alignment % page_size);
28+
address = AlignedAddress(address, alignment);
29+
// Add the maximum misalignment so we are guaranteed an aligned base address.
30+
size_t request_size = size + (alignment - page_size);
5331

5432
zx_handle_t vmo;
5533
if (zx_vmo_create(request_size, 0, &vmo) != ZX_OK) {
56-
*allocated = 0;
5734
return nullptr;
5835
}
5936
static const char kVirtualMemoryName[] = "v8-virtualmem";
@@ -66,26 +43,25 @@ void* OS::ReserveAlignedRegion(size_t size, size_t alignment, void* hint,
6643
// so close the vmo either way.
6744
zx_handle_close(vmo);
6845
if (status != ZX_OK) {
69-
*allocated = 0;
7046
return nullptr;
7147
}
7248

7349
uint8_t* base = reinterpret_cast<uint8_t*>(reservation);
7450
uint8_t* aligned_base = RoundUp(base, alignment);
75-
DCHECK_LE(base, aligned_base);
7651

7752
// Unmap extra memory reserved before and after the desired block.
7853
if (aligned_base != base) {
54+
DCHECK_LT(base, aligned_base);
7955
size_t prefix_size = static_cast<size_t>(aligned_base - base);
8056
zx_vmar_unmap(zx_vmar_root_self(), reinterpret_cast<uintptr_t>(base),
8157
prefix_size);
8258
request_size -= prefix_size;
8359
}
8460

85-
size_t aligned_size = RoundUp(size, OS::AllocatePageSize());
86-
DCHECK_LE(aligned_size, request_size);
61+
size_t aligned_size = RoundUp(size, page_size);
8762

8863
if (aligned_size != request_size) {
64+
DCHECK_LT(aligned_size, request_size);
8965
size_t suffix_size = request_size - aligned_size;
9066
zx_vmar_unmap(zx_vmar_root_self(),
9167
reinterpret_cast<uintptr_t>(aligned_base + aligned_size),
@@ -94,11 +70,16 @@ void* OS::ReserveAlignedRegion(size_t size, size_t alignment, void* hint,
9470
}
9571

9672
DCHECK(aligned_size == request_size);
97-
98-
*allocated = aligned_size;
9973
return static_cast<void*>(aligned_base);
10074
}
10175

76+
// static
77+
void OS::Guard(void* address, size_t size) {
78+
CHECK_EQ(ZX_OK, zx_vmar_protect(zx_vmar_root_self(),
79+
reinterpret_cast<uintptr_t>(address), size,
80+
0 /*no permissions*/));
81+
}
82+
10283
// static
10384
bool OS::CommitRegion(void* address, size_t size, bool is_executable) {
10485
uint32_t prot = ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE |

0 commit comments

Comments
 (0)