Revert "cppgc: Rework prefinalizers"

This reverts commit cf25b3bc53.

Reason for revert: https://crbug.com/1307471. TraceTrait must only be used during marking.

Original change's description:
> cppgc: Rework prefinalizers
>
> Move the check for whether an object is live or dead out of the
> prefinalizer trampoline. Moving it into the backend allows for
> inlining the check which avoids a call to the trampoline for live
> objects.
>
> On catapult benchmarks (e.g. cnn:2021, nytimes:2020), there's often
> ~2k finalizers registered. In order to avoid memory overhead in the
> range of a few KB, we store the fact whether the object points to the
> base object payload in the LSB of the pointer. For caged builds this
> is replaced with just storing the index into the cage for both object
> and base object payload.
>
> Locally saves around ~10% of atomic sweeping processing time which is
> in the order of .05ms.
>
> Bug: v8:12698
> Change-Id: I198205a6b1d57fc2df821ee4e73e53dc6f825ff5
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3497764
> Reviewed-by: Omer Katz <omerkatz@chromium.org>
> Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#79442}

Bug: v8:12698, chromium:1307471
Change-Id: I5c4e70d46cb99af66c77f0c013625b6af6c6eb8e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3535781
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79527}
This commit is contained in:
Michael Lippautz 2022-03-18 07:44:06 +00:00 committed by V8 LUCI CQ
parent bbea5909c7
commit f46c4858b0
5 changed files with 29 additions and 128 deletions

View File

@ -14,9 +14,9 @@ namespace internal {
class V8_EXPORT PrefinalizerRegistration final {
public:
using Callback = void (*)(void*);
using Callback = bool (*)(const cppgc::LivenessBroker&, void*);
PrefinalizerRegistration(void*, const void*, Callback);
PrefinalizerRegistration(void*, Callback);
void* operator new(size_t, void* location) = delete;
void* operator new(size_t) = delete;
@ -53,21 +53,21 @@ class V8_EXPORT PrefinalizerRegistration final {
* };
* \endcode
*/
#define CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer) \
public: \
static void InvokePreFinalizer(void* object) { \
static_assert(cppgc::IsGarbageCollectedOrMixinTypeV<Class>, \
"Only garbage collected objects can have prefinalizers"); \
Class* self = static_cast<Class*>(object); \
self->PreFinalizer(); \
} \
\
private: \
CPPGC_NO_UNIQUE_ADDRESS cppgc::internal::PrefinalizerRegistration \
prefinalizer_dummy_{this, \
cppgc::TraceTrait<Class>::GetTraceDescriptor(this) \
.base_object_payload, \
Class::InvokePreFinalizer}; \
#define CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer) \
public: \
static bool InvokePreFinalizer(const cppgc::LivenessBroker& liveness_broker, \
void* object) { \
static_assert(cppgc::IsGarbageCollectedOrMixinTypeV<Class>, \
"Only garbage collected objects can have prefinalizers"); \
Class* self = static_cast<Class*>(object); \
if (liveness_broker.IsHeapObjectAlive(self)) return false; \
self->PreFinalizer(); \
return true; \
} \
\
private: \
CPPGC_NO_UNIQUE_ADDRESS cppgc::internal::PrefinalizerRegistration \
prefinalizer_dummy_{this, Class::InvokePreFinalizer}; \
static_assert(true, "Force semicolon.")
} // namespace cppgc

View File

@ -43,7 +43,6 @@ class PointerWithPayload {
explicit PointerWithPayload(PointerType* pointer)
: pointer_with_payload_(reinterpret_cast<uintptr_t>(pointer)) {
DCHECK_EQ(reinterpret_cast<uintptr_t>(pointer) & kPayloadMask, 0);
DCHECK_EQ(GetPointer(), pointer);
DCHECK_EQ(GetPayload(), static_cast<PayloadType>(0));
}
@ -58,11 +57,6 @@ class PointerWithPayload {
Update(pointer, payload);
}
PointerWithPayload(const PointerWithPayload& other) V8_NOEXCEPT = default;
PointerWithPayload& operator=(const PointerWithPayload& other)
V8_NOEXCEPT = default;
V8_INLINE PointerType* GetPointer() const {
return reinterpret_cast<PointerType*>(pointer_with_payload_ & kPointerMask);
}
@ -77,18 +71,17 @@ class PointerWithPayload {
V8_INLINE PointerType* operator->() const { return GetPointer(); }
V8_INLINE void Update(PointerType* new_pointer, PayloadType new_payload) {
DCHECK_EQ(reinterpret_cast<uintptr_t>(new_pointer) & kPayloadMask, 0);
pointer_with_payload_ = reinterpret_cast<uintptr_t>(new_pointer) |
static_cast<uintptr_t>(new_payload);
DCHECK_EQ(GetPayload(), new_payload);
DCHECK_EQ(GetPointer(), new_pointer);
}
V8_INLINE void SetPointer(PointerType* new_pointer) {
DCHECK_EQ(reinterpret_cast<uintptr_t>(new_pointer) & kPayloadMask, 0);
pointer_with_payload_ = reinterpret_cast<uintptr_t>(new_pointer) |
V8_INLINE void SetPointer(PointerType* newptr) {
DCHECK_EQ(reinterpret_cast<uintptr_t>(newptr) & kPayloadMask, 0);
pointer_with_payload_ = reinterpret_cast<uintptr_t>(newptr) |
(pointer_with_payload_ & kPayloadMask);
DCHECK_EQ(GetPointer(), new_pointer);
DCHECK_EQ(GetPointer(), newptr);
}
V8_INLINE PayloadType GetPayload() const {
@ -117,15 +110,6 @@ class PointerWithPayload {
static constexpr uintptr_t kPointerMask = ~kPayloadMask;
uintptr_t pointer_with_payload_ = 0;
friend bool operator==(const PointerWithPayload& p1,
const PointerWithPayload& p2) {
return p1.pointer_with_payload_ == p2.pointer_with_payload_;
}
friend bool operator!=(const PointerWithPayload& p1,
const PointerWithPayload& p2) {
return !(p1 == p2);
}
};
} // namespace base

View File

@ -10,7 +10,6 @@
#include "include/cppgc/platform.h"
#include "src/base/bounded-page-allocator.h"
#include "src/base/logging.h"
#include "src/heap/cppgc/globals.h"
#include "src/heap/cppgc/virtual-memory.h"
@ -33,12 +32,6 @@ class CagedHeap final {
(kCagedHeapReservationAlignment - 1);
}
static void* AddressFromOffset(void* base, size_t offset) {
DCHECK_LT(offset, kCagedHeapReservationSize);
DCHECK_NOT_NULL(base);
return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(base) + offset);
}
static uintptr_t BaseFromAddress(const void* address) {
return reinterpret_cast<uintptr_t>(address) &
~(kCagedHeapReservationAlignment - 1);

View File

@ -8,8 +8,6 @@
#include <memory>
#include "src/base/platform/platform.h"
#include "src/base/pointer-with-payload.h"
#include "src/heap/cppgc/heap-object-header.h"
#include "src/heap/cppgc/heap-page.h"
#include "src/heap/cppgc/heap.h"
#include "src/heap/cppgc/liveness-broker.h"
@ -18,37 +16,15 @@
namespace cppgc {
namespace internal {
PrefinalizerRegistration::PrefinalizerRegistration(
void* object, const void* base_object_payload, Callback callback) {
PrefinalizerRegistration::PrefinalizerRegistration(void* object,
Callback callback) {
auto* page = BasePage::FromPayload(object);
DCHECK(!page->space().is_compactable());
page->heap().prefinalizer_handler()->RegisterPrefinalizer(
PreFinalizer(object, base_object_payload, callback));
page->heap().prefinalizer_handler()->RegisterPrefinalizer({object, callback});
}
bool PreFinalizer::operator==(const PreFinalizer& other) const {
return
#if defined(CPPGC_CAGED_HEAP)
(object_offset == other.object_offset)
#else // !defined(CPPGC_CAGED_HEAP)
(object_and_offset == other.object_and_offset)
#endif // !defined(CPPGC_CAGED_HEAP)
&& (callback == other.callback);
}
PreFinalizer::PreFinalizer(void* object, const void* base_object_payload,
Callback cb)
:
#if defined(CPPGC_CAGED_HEAP)
object_offset(CagedHeap::OffsetFromAddress<uint32_t>(object)),
base_object_payload_offset(
CagedHeap::OffsetFromAddress<uint32_t>(base_object_payload)),
#else // !defined(CPPGC_CAGED_HEAP)
object_and_offset(object, (object == base_object_payload)
? PointerType::kAtBase
: PointerType::kInnerPointer),
#endif // !defined(CPPGC_CAGED_HEAP)
callback(cb) {
return (object == other.object) && (callback == other.callback);
}
PreFinalizerHandler::PreFinalizerHandler(HeapBase& heap)
@ -72,33 +48,6 @@ void PreFinalizerHandler::RegisterPrefinalizer(PreFinalizer pre_finalizer) {
current_ordered_pre_finalizers_->push_back(pre_finalizer);
}
namespace {
// Returns true in case the prefinalizer was invoked.
V8_INLINE bool InvokeUnmarkedPrefinalizers(void* cage_base,
const PreFinalizer& pf) {
#if defined(CPPGC_CAGED_HEAP)
void* object = CagedHeap::AddressFromOffset(cage_base, pf.object_offset);
void* base_object_payload =
CagedHeap::AddressFromOffset(cage_base, pf.base_object_payload_offset);
#else // !defined(CPPGC_CAGED_HEAP)
void* object = pf.object_and_offset.GetPointer();
void* base_object_payload =
pf.object_and_offset.GetPayload() == PreFinalizer::PointerType::kAtBase
? object
: reinterpret_cast<void*>(BasePage::FromPayload(object)
->ObjectHeaderFromInnerAddress(object)
.ObjectStart());
#endif // !defined(CPPGC_CAGED_HEAP)
if (HeapObjectHeader::FromObject(base_object_payload).IsMarked())
return false;
pf.callback(object);
return true;
}
} // namespace
void PreFinalizerHandler::InvokePreFinalizers() {
StatsCollector::EnabledScope stats_scope(heap_.stats_collector(),
StatsCollector::kAtomicSweep);
@ -106,15 +55,11 @@ void PreFinalizerHandler::InvokePreFinalizers() {
heap_.stats_collector(), StatsCollector::kSweepInvokePreFinalizers);
DCHECK(CurrentThreadIsCreationThread());
LivenessBroker liveness_broker = LivenessBrokerFactory::Create();
is_invoking_ = true;
DCHECK_EQ(0u, bytes_allocated_in_prefinalizers);
// Reset all LABs to force allocations to the slow path for black allocation.
heap_.object_allocator().ResetLinearAllocationBuffers();
void* cage_base = nullptr;
#if defined(CPPGC_CAGED_HEAP)
cage_base = heap_.caged_heap().base();
#endif // defined(CPPGC_CAGED_HEAP)
// Prefinalizers can allocate other objects with prefinalizers, which will
// modify ordered_pre_finalizers_ and break iterators.
std::vector<PreFinalizer> new_ordered_pre_finalizers;
@ -123,8 +68,8 @@ void PreFinalizerHandler::InvokePreFinalizers() {
ordered_pre_finalizers_.begin(),
std::remove_if(ordered_pre_finalizers_.rbegin(),
ordered_pre_finalizers_.rend(),
[cage_base](const PreFinalizer& pf) {
return InvokeUnmarkedPrefinalizers(cage_base, pf);
[liveness_broker](const PreFinalizer& pf) {
return (pf.callback)(liveness_broker, pf.object);
})
.base());
// Newly added objects with prefinalizers will always survive the current GC

View File

@ -9,7 +9,6 @@
#include <vector>
#include "include/cppgc/prefinalizer.h"
#include "src/base/pointer-with-payload.h"
namespace cppgc {
namespace internal {
@ -19,27 +18,7 @@ class HeapBase;
struct PreFinalizer final {
using Callback = PrefinalizerRegistration::Callback;
PreFinalizer(void* object, const void* base_object_payload,
Callback callback);
#if defined(CPPGC_CAGED_HEAP)
uint32_t object_offset;
uint32_t base_object_payload_offset;
#else // !defined(CPPGC_CAGED_HEAP)
enum class PointerType : uint8_t {
kAtBase,
kInnerPointer,
};
// Contains the pointer and also an indicator of whether the pointer points to
// the base of the object or is an inner pointer.
v8::base::PointerWithPayload<void, PointerType, 1> object_and_offset;
#endif // !defined(CPPGC_CAGED_HEAP)
void* object;
Callback callback;
bool operator==(const PreFinalizer& other) const;