Commit 66cfc315 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

cppgc: Provide basic allocation to have access to Heap backref

This CL provides a basic allocator that allocates normal-sized objects
on pages without ever reusing them. This allows for already using the
backref from page to heap which is used in some critical places
(pre-finalizers, write barrier, Persistent).

Bug: chromium:1056170
Change-Id: Ifada9b7e984827906c267d1a3a521576587feaeb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2141736
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarAnton Bikineev <bikineev@chromium.org>
Reviewed-by: 's avatarOmer Katz <omerkatz@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67076}
parent bedf467c
......@@ -3948,6 +3948,7 @@ v8_source_set("cppgc_base") {
"include/cppgc/allocation.h",
"include/cppgc/garbage-collected.h",
"include/cppgc/heap.h",
"include/cppgc/internal/accessors.h",
"include/cppgc/internal/api-contants.h",
"include/cppgc/internal/finalizer-traits.h",
"include/cppgc/internal/gc-info.h",
......@@ -3967,6 +3968,8 @@ v8_source_set("cppgc_base") {
"src/heap/cppgc/heap-object-header-inl.h",
"src/heap/cppgc/heap-object-header.cc",
"src/heap/cppgc/heap-object-header.h",
"src/heap/cppgc/heap-page.cc",
"src/heap/cppgc/heap-page.h",
"src/heap/cppgc/heap.cc",
"src/heap/cppgc/heap.h",
"src/heap/cppgc/platform.cc",
......
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_INTERNAL_ACCESSORS_H_
#define INCLUDE_CPPGC_INTERNAL_ACCESSORS_H_
#include "include/cppgc/heap.h"
#include "include/cppgc/internal/api-constants.h"
namespace cppgc {
namespace internal {
inline cppgc::Heap* GetHeapFromPayload(const void* payload) {
return reinterpret_cast<cppgc::Heap*>(
(reinterpret_cast<uintptr_t>(payload) & api_constants::kPageBaseMask) +
api_constants::kHeapOffset);
}
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_ACCESSORS_H_
......@@ -25,7 +25,15 @@ static constexpr size_t kFullyConstructedBitFieldOffsetFromPayload =
// Mask for in-construction bit.
static constexpr size_t kFullyConstructedBitMask = size_t{1};
static constexpr size_t kLargeObjectSizeThreshold = 65536;
// Page constants used to align pointers to page begin.
static constexpr size_t kPageSize = size_t{1} << 17;
static constexpr size_t kPageAlignment = kPageSize;
static constexpr size_t kPageBaseMask = ~(kPageAlignment - 1);
// Offset of the Heap backref.
static constexpr size_t kHeapOffset = 0;
static constexpr size_t kLargeObjectSizeThreshold = kPageSize / 2;
} // namespace api_constants
......
......@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_HEAP_CPPGC_HEAP_INL_H_
#define V8_HEAP_CPPGC_HEAP_INL_H_
#include "src/heap/cppgc/heap.h"
#include "src/heap/cppgc/globals.h"
#include "src/heap/cppgc/heap-object-header-inl.h"
#ifndef V8_HEAP_CPPGC_HEAP_INL_H_
#define V8_HEAP_CPPGC_HEAP_INL_H_
namespace cppgc {
namespace internal {
......@@ -23,13 +23,24 @@ void* Heap::Allocate(size_t size, GCInfoIndex index) {
// a multiple of kAllocationGranularity to follow restrictions of
// HeapObjectHeader.
allocation_size = (allocation_size + kAllocationMask) & ~kAllocationMask;
void* memory = calloc(1, allocation_size);
void* memory = allocator_->Allocate(allocation_size);
HeapObjectHeader* header =
new (memory) HeapObjectHeader(allocation_size, index);
objects_.push_back(header);
return header->Payload();
}
void* Heap::BasicAllocator::Allocate(size_t size) {
// Can only allocate normal-sized objects.
CHECK_GT(kLargeObjectSizeThreshold, size);
if (current_ == nullptr || (current_ + size) > limit_) {
GetNewPage();
}
void* memory = current_;
current_ += size;
return memory;
}
} // namespace internal
} // namespace cppgc
......
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/heap/cppgc/heap-page.h"
#include "include/cppgc/internal/api-constants.h"
#include "src/heap/cppgc/globals.h"
namespace cppgc {
namespace internal {
namespace {
Address AlignAddress(Address address, size_t alignment) {
return reinterpret_cast<Address>(
RoundUp(reinterpret_cast<uintptr_t>(address), alignment));
}
} // namespace
STATIC_ASSERT(kPageSize == api_constants::kPageAlignment);
BasePage::BasePage(Heap* heap) : heap_(heap) {
DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(this) & kPageOffsetMask);
DCHECK_EQ(reinterpret_cast<void*>(&heap_),
FromPayload(this) + api_constants::kHeapOffset);
}
// static
BasePage* BasePage::FromPayload(const void* payload) {
return reinterpret_cast<BasePage*>(
reinterpret_cast<uintptr_t>(const_cast<void*>(payload)) & kPageBaseMask);
}
// static
NormalPage* NormalPage::Create(Heap* heap) {
Address reservation = reinterpret_cast<Address>(calloc(1, 2 * kPageSize));
return new (AlignAddress(reservation, kPageSize))
NormalPage(heap, reservation);
}
// static
void NormalPage::Destroy(NormalPage* page) {
Address reservation = page->reservation_;
page->~NormalPage();
free(reservation);
}
NormalPage::NormalPage(Heap* heap, Address reservation)
: BasePage(heap),
reservation_(reservation),
payload_start_(AlignAddress(reinterpret_cast<Address>(this + 1),
kAllocationGranularity)),
payload_end_(reinterpret_cast<Address>(this) + kPageSize) {
DCHECK_GT(PayloadEnd() - PayloadStart(), kLargeObjectSizeThreshold);
}
} // namespace internal
} // namespace cppgc
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_HEAP_CPPGC_HEAP_PAGE_H_
#define V8_HEAP_CPPGC_HEAP_PAGE_H_
#include "src/base/macros.h"
#include "src/heap/cppgc/globals.h"
#include "src/heap/cppgc/heap.h"
namespace cppgc {
namespace internal {
class V8_EXPORT_PRIVATE BasePage {
public:
static BasePage* FromPayload(const void*);
protected:
explicit BasePage(Heap* heap);
Heap* heap_;
};
class V8_EXPORT_PRIVATE NormalPage final : public BasePage {
public:
static NormalPage* Create(Heap* heap);
static void Destroy(NormalPage*);
Address PayloadStart() const { return payload_start_; }
Address PayloadEnd() const { return payload_end_; }
private:
explicit NormalPage(Heap* heap, Address reservation);
Address reservation_;
Address payload_start_;
Address payload_end_;
};
} // namespace internal
} // namespace cppgc
#endif // V8_HEAP_CPPGC_HEAP_PAGE_H_
......@@ -8,6 +8,7 @@
#include "src/base/platform/platform.h"
#include "src/heap/cppgc/heap-object-header-inl.h"
#include "src/heap/cppgc/heap-page.h"
#include "src/heap/cppgc/stack.h"
namespace cppgc {
......@@ -47,12 +48,12 @@ class StackMarker final : public StackVisitor {
};
Heap::Heap()
: stack_(std::make_unique<Stack>(v8::base::Stack::GetStackStart())) {}
: stack_(std::make_unique<Stack>(v8::base::Stack::GetStackStart())),
allocator_(std::make_unique<BasicAllocator>(this)) {}
Heap::~Heap() {
for (HeapObjectHeader* header : objects_) {
header->Finalize();
free(header);
}
}
......@@ -74,7 +75,6 @@ void Heap::CollectGarbage(GCConfig config) {
++it;
} else {
header->Finalize();
free(header);
it = objects_.erase(it);
}
}
......@@ -84,5 +84,21 @@ Heap::NoGCScope::NoGCScope(Heap* heap) : heap_(heap) { heap_->no_gc_scope_++; }
Heap::NoGCScope::~NoGCScope() { heap_->no_gc_scope_--; }
Heap::BasicAllocator::BasicAllocator(Heap* heap) : heap_(heap) {}
Heap::BasicAllocator::~BasicAllocator() {
for (auto* page : used_pages_) {
NormalPage::Destroy(page);
}
}
void Heap::BasicAllocator::GetNewPage() {
auto* page = NormalPage::Create(heap_);
CHECK(page);
used_pages_.push_back(page);
current_ = page->PayloadStart();
limit_ = page->PayloadEnd();
}
} // namespace internal
} // namespace cppgc
......@@ -15,6 +15,7 @@
namespace cppgc {
namespace internal {
class NormalPage;
class Stack;
class V8_EXPORT_PRIVATE Heap final : public cppgc::Heap {
......@@ -49,9 +50,31 @@ class V8_EXPORT_PRIVATE Heap final : public cppgc::Heap {
void CollectGarbage(GCConfig config = GCConfig::Default());
private:
// TODO(chromium:1056170): Remove as soon as arenas are available for
// allocation.
//
// This basic allocator just gets a page from the backend and uses bump
// pointer allocation in the payload to allocate objects. No memory is
// reused across GC calls.
class BasicAllocator final {
public:
explicit BasicAllocator(Heap* heap);
~BasicAllocator();
inline void* Allocate(size_t);
private:
void GetNewPage();
Heap* heap_;
Address current_ = nullptr;
Address limit_ = nullptr;
std::vector<NormalPage*> used_pages_;
};
bool in_no_gc_scope() { return no_gc_scope_ > 0; }
std::unique_ptr<Stack> stack_;
std::unique_ptr<BasicAllocator> allocator_;
std::vector<HeapObjectHeader*> objects_;
size_t no_gc_scope_ = 0;
......
......@@ -48,6 +48,7 @@ v8_source_set("cppgc_unittests_sources") {
"heap/cppgc/garbage-collected_unittest.cc",
"heap/cppgc/gc-info_unittest.cc",
"heap/cppgc/heap-object-header_unittest.cc",
"heap/cppgc/heap-page_unittest.cc",
"heap/cppgc/heap_unittest.cc",
"heap/cppgc/member_unittests.cc",
"heap/cppgc/source-location_unittest.cc",
......
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/heap/cppgc/heap-page.h"
#include "test/unittests/heap/cppgc/tests.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cppgc {
namespace internal {
namespace {
class PageTest : public testing::TestWithHeap {};
} // namespace
TEST_F(PageTest, PageLayout) {
auto* np = NormalPage::Create(Heap::From(GetHeap()));
NormalPage::Destroy(np);
}
} // namespace internal
} // namespace cppgc
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