Commit 8cd72a71 authored by Hannes Payer's avatar Hannes Payer Committed by Commit Bot

[heap] Reland register executable MemoryChunks.

Bug: chromium:774108,v8:6792
Change-Id: I4736b86ad5bd5e0777dc7a121023c4ed34d69fb0
Reviewed-on: https://chromium-review.googlesource.com/873170
Commit-Queue: Hannes Payer <hpayer@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50683}
parent 8432d381
...@@ -626,6 +626,7 @@ CodeSpaceMemoryModificationScope::CodeSpaceMemoryModificationScope(Heap* heap) ...@@ -626,6 +626,7 @@ CodeSpaceMemoryModificationScope::CodeSpaceMemoryModificationScope(Heap* heap)
LargePage* page = heap_->lo_space()->first_page(); LargePage* page = heap_->lo_space()->first_page();
while (page != nullptr) { while (page != nullptr) {
if (page->IsFlagSet(MemoryChunk::IS_EXECUTABLE)) { if (page->IsFlagSet(MemoryChunk::IS_EXECUTABLE)) {
CHECK(heap_->memory_allocator()->IsMemoryChunkExecutable(page));
page->SetReadAndWritable(); page->SetReadAndWritable();
} }
page = page->next_page(); page = page->next_page();
...@@ -640,6 +641,7 @@ CodeSpaceMemoryModificationScope::~CodeSpaceMemoryModificationScope() { ...@@ -640,6 +641,7 @@ CodeSpaceMemoryModificationScope::~CodeSpaceMemoryModificationScope() {
LargePage* page = heap_->lo_space()->first_page(); LargePage* page = heap_->lo_space()->first_page();
while (page != nullptr) { while (page != nullptr) {
if (page->IsFlagSet(MemoryChunk::IS_EXECUTABLE)) { if (page->IsFlagSet(MemoryChunk::IS_EXECUTABLE)) {
CHECK(heap_->memory_allocator()->IsMemoryChunkExecutable(page));
page->SetReadAndExecutable(); page->SetReadAndExecutable();
} }
page = page->next_page(); page = page->next_page();
......
...@@ -2658,6 +2658,7 @@ class AlwaysAllocateScope { ...@@ -2658,6 +2658,7 @@ class AlwaysAllocateScope {
Heap* heap_; Heap* heap_;
}; };
// The CodeSpaceMemoryModificationScope can only be used by the main thread.
class CodeSpaceMemoryModificationScope { class CodeSpaceMemoryModificationScope {
public: public:
explicit inline CodeSpaceMemoryModificationScope(Heap* heap); explicit inline CodeSpaceMemoryModificationScope(Heap* heap);
...@@ -2667,6 +2668,9 @@ class CodeSpaceMemoryModificationScope { ...@@ -2667,6 +2668,9 @@ class CodeSpaceMemoryModificationScope {
Heap* heap_; Heap* heap_;
}; };
// The CodePageMemoryModificationScope does not check if tansitions to
// writeable and back to executable are actually allowed, i.e. the MemoryChunk
// was registered to be executable. It can be used by concurrent threads.
class CodePageMemoryModificationScope { class CodePageMemoryModificationScope {
public: public:
explicit inline CodePageMemoryModificationScope(MemoryChunk* chunk); explicit inline CodePageMemoryModificationScope(MemoryChunk* chunk);
......
...@@ -826,8 +826,13 @@ MemoryChunk* MemoryAllocator::AllocateChunk(size_t reserve_area_size, ...@@ -826,8 +826,13 @@ MemoryChunk* MemoryAllocator::AllocateChunk(size_t reserve_area_size,
owner); owner);
} }
return MemoryChunk::Initialize(heap, base, chunk_size, area_start, area_end, MemoryChunk* chunk =
MemoryChunk::Initialize(heap, base, chunk_size, area_start, area_end,
executable, owner, &reservation); executable, owner, &reservation);
if (chunk->executable()) RegisterExecutableMemoryChunk(chunk);
return chunk;
} }
void Page::ResetAllocatedBytes() { allocated_bytes_ = area_size(); } void Page::ResetAllocatedBytes() { allocated_bytes_ = area_size(); }
...@@ -970,6 +975,8 @@ void MemoryAllocator::PreFreeMemory(MemoryChunk* chunk) { ...@@ -970,6 +975,8 @@ void MemoryAllocator::PreFreeMemory(MemoryChunk* chunk) {
} }
chunk->SetFlag(MemoryChunk::PRE_FREED); chunk->SetFlag(MemoryChunk::PRE_FREED);
if (chunk->executable()) UnregisterExecutableMemoryChunk(chunk);
} }
...@@ -1722,6 +1729,7 @@ void PagedSpace::ReleasePage(Page* page) { ...@@ -1722,6 +1729,7 @@ void PagedSpace::ReleasePage(Page* page) {
void PagedSpace::SetReadAndExecutable() { void PagedSpace::SetReadAndExecutable() {
DCHECK(identity() == CODE_SPACE); DCHECK(identity() == CODE_SPACE);
for (Page* page : *this) { for (Page* page : *this) {
CHECK(heap_->memory_allocator()->IsMemoryChunkExecutable(page));
page->SetReadAndExecutable(); page->SetReadAndExecutable();
} }
} }
...@@ -1729,6 +1737,7 @@ void PagedSpace::SetReadAndExecutable() { ...@@ -1729,6 +1737,7 @@ void PagedSpace::SetReadAndExecutable() {
void PagedSpace::SetReadAndWritable() { void PagedSpace::SetReadAndWritable() {
DCHECK(identity() == CODE_SPACE); DCHECK(identity() == CODE_SPACE);
for (Page* page : *this) { for (Page* page : *this) {
CHECK(heap_->memory_allocator()->IsMemoryChunkExecutable(page));
page->SetReadAndWritable(); page->SetReadAndWritable();
} }
} }
......
...@@ -1359,6 +1359,12 @@ class V8_EXPORT_PRIVATE MemoryAllocator { ...@@ -1359,6 +1359,12 @@ class V8_EXPORT_PRIVATE MemoryAllocator {
// and false otherwise. // and false otherwise.
bool CommitBlock(Address start, size_t size, Executability executable); bool CommitBlock(Address start, size_t size, Executability executable);
// Checks if an allocated MemoryChunk was intended to be used for executable
// memory.
bool IsMemoryChunkExecutable(MemoryChunk* chunk) {
return executable_memory_.find(chunk) != executable_memory_.end();
}
// Uncommit a contiguous block of memory [start..(start+size)[. // Uncommit a contiguous block of memory [start..(start+size)[.
// start is not nullptr, the size is greater than zero, and the // start is not nullptr, the size is greater than zero, and the
// block is contained in the initial chunk. Returns true if it succeeded // block is contained in the initial chunk. Returns true if it succeeded
...@@ -1409,6 +1415,17 @@ class V8_EXPORT_PRIVATE MemoryAllocator { ...@@ -1409,6 +1415,17 @@ class V8_EXPORT_PRIVATE MemoryAllocator {
} while ((high > ptr) && !highest_ever_allocated_.TrySetValue(ptr, high)); } while ((high > ptr) && !highest_ever_allocated_.TrySetValue(ptr, high));
} }
void RegisterExecutableMemoryChunk(MemoryChunk* chunk) {
DCHECK(chunk->IsFlagSet(MemoryChunk::IS_EXECUTABLE));
DCHECK_EQ(executable_memory_.find(chunk), executable_memory_.end());
executable_memory_.insert(chunk);
}
void UnregisterExecutableMemoryChunk(MemoryChunk* chunk) {
DCHECK_NE(executable_memory_.find(chunk), executable_memory_.end());
executable_memory_.erase(chunk);
}
Isolate* isolate_; Isolate* isolate_;
CodeRange* code_range_; CodeRange* code_range_;
...@@ -1431,6 +1448,9 @@ class V8_EXPORT_PRIVATE MemoryAllocator { ...@@ -1431,6 +1448,9 @@ class V8_EXPORT_PRIVATE MemoryAllocator {
VirtualMemory last_chunk_; VirtualMemory last_chunk_;
Unmapper unmapper_; Unmapper unmapper_;
// Data structure to remember allocated executable memory chunks.
std::unordered_set<MemoryChunk*> executable_memory_;
friend class heap::TestCodeRangeScope; friend class heap::TestCodeRangeScope;
DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryAllocator); DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryAllocator);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment