Commit e2059e53 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

heap: Introduce not fully constructed state for objects during ctor

Use the MakeGarbageCollected bottleneck to flag objects as being under
construction while their constructor is executed.

can be recovered once we are done moving to MakeGarbagecollected by
opening the scope in the allocator (HoH ctor).

Binary-Size: Increase due to adding scope to constructors. Roughly 50%
Bug: 843903
Change-Id: I0a5182481534922ba14c6c12ed7138dadbcadea5
Reviewed-on: https://chromium-review.googlesource.com/c/1350128
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarHannes Payer <hpayer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611659}
parent 573c7434
......@@ -534,10 +534,14 @@ class ConstructTrait<T, false> {
public:
template <typename... Args>
static T* Construct(Args&&... args) {
void* memory =
T::AllocateObject(sizeof(T), IsEagerlyFinalizedType<T>::value);
HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
header->MarkIsInConstruction();
// Placement new as regular operator new() is deleted.
return ::new (
T::AllocateObject(sizeof(T), IsEagerlyFinalizedType<T>::value))
T(std::forward<Args>(args)...);
T* object = ::new (memory) T(std::forward<Args>(args)...);
header->UnmarkIsInConstruction();
return object;
}
};
......@@ -545,9 +549,19 @@ template <typename T>
class ConstructTrait<T, true> {
public:
template <typename... Args>
static T* Construct(Args&&... args) {
// TODO(mlippautz): Inline GarbageCollectedMixin::operator new() here.
return new T(std::forward<Args>(args)...);
NO_SANITIZE_UNRELATED_CAST static T* Construct(Args&&... args) {
void* memory =
T::AllocateObject(sizeof(T), IsEagerlyFinalizedType<T>::value);
HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
header->MarkIsInConstruction();
ThreadState* state =
ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
state->EnterGCForbiddenScopeIfNeeded(
&(reinterpret_cast<T*>(memory)->mixin_constructor_marker_));
// Placement new as regular operator new() is deleted.
T* object = ::new (memory) T(std::forward<Args>(args)...);
header->UnmarkIsInConstruction();
return object;
}
};
......
......@@ -148,7 +148,7 @@ uint32_t ComputeRandomMagic();
//
// | random magic value (32 bits) | Only present on 64-bit platforms.
// | gc_info_index (14 bits) |
// | unused (1 bit) |
// | in construction (1 bit) |
// | size (14 bits) | Actually 17 bits because sizes are aligned.
// | wrapper mark bit (1 bit) |
// | unused (1 bit) |
......@@ -166,7 +166,7 @@ constexpr uint32_t kHeaderMarkBitMask = 1;
constexpr uint32_t kHeaderUnusedBit1Mask = 2;
constexpr uint32_t kHeaderWrapperMarkBitMask = 4;
constexpr uint32_t kHeaderSizeMask = ((uint32_t{1} << 14) - 1) << 3;
constexpr uint32_t kHeaderUnusedBit2Mask = uint32_t{1} << 17;
constexpr uint32_t kHeaderIsInConstructionMask = uint32_t{1} << 17;
constexpr uint32_t kHeaderGCInfoIndexShift = 18;
constexpr uint32_t kHeaderGCInfoSize = uint32_t{1} << 14;
constexpr uint32_t kHeaderGCInfoIndexMask = (kHeaderGCInfoSize - 1)
......@@ -225,6 +225,10 @@ class PLATFORM_EXPORT HeapObjectHeader {
void Unmark();
bool TryMark();
void MarkIsInConstruction();
void UnmarkIsInConstruction();
bool IsInConstruction() const;
// The payload starts directly after the HeapObjectHeader, and the payload
// size does not include the sizeof(HeapObjectHeader).
Address Payload();
......@@ -917,6 +921,20 @@ NO_SANITIZE_ADDRESS inline void HeapObjectHeader::SetSize(size_t size) {
encoded_ = static_cast<uint32_t>(size) | (encoded_ & ~kHeaderSizeMask);
}
NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::IsInConstruction() const {
return encoded_ & kHeaderIsInConstructionMask;
}
NO_SANITIZE_ADDRESS inline void HeapObjectHeader::MarkIsInConstruction() {
DCHECK(!IsInConstruction());
encoded_ = encoded_ | kHeaderIsInConstructionMask;
}
NO_SANITIZE_ADDRESS inline void HeapObjectHeader::UnmarkIsInConstruction() {
DCHECK(IsInConstruction());
encoded_ = encoded_ & ~kHeaderIsInConstructionMask;
}
NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::IsValid() const {
#if defined(ARCH_CPU_64_BITS)
return GetMagic() == magic_;
......
......@@ -6822,4 +6822,61 @@ TEST(HeapTest, NoConservativeGCDuringMixinConstruction) {
MakeGarbageCollected<UsingMixinCheckingConstructionScope>();
}
namespace {
class ObjectCheckingForInConstruction
: public GarbageCollected<ObjectCheckingForInConstruction> {
public:
ObjectCheckingForInConstruction() {
CHECK(HeapObjectHeader::FromPayload(this)->IsInConstruction());
}
virtual void Trace(Visitor* v) { v->Trace(foo_); }
private:
Member<IntWrapper> foo_;
};
class MixinCheckingInConstruction : public GarbageCollectedMixin {
public:
MixinCheckingInConstruction() {
BasePage* const page = PageFromObject(reinterpret_cast<Address>(this));
HeapObjectHeader* const header =
static_cast<NormalPage*>(page)->FindHeaderFromAddress(
reinterpret_cast<Address>(
const_cast<MixinCheckingInConstruction*>(this)));
CHECK(header->IsInConstruction());
}
void Trace(Visitor* v) override { v->Trace(bar_); }
private:
Member<IntWrapper> bar_;
};
class MixinAppCheckingInConstruction
: public GarbageCollected<MixinAppCheckingInConstruction>,
public MixinCheckingInConstruction {
USING_GARBAGE_COLLECTED_MIXIN(MixinAppCheckingInConstruction)
public:
MixinAppCheckingInConstruction() {
CHECK(HeapObjectHeader::FromPayload(this)->IsInConstruction());
}
void Trace(Visitor* v) override { v->Trace(foo_); }
private:
Member<IntWrapper> foo_;
};
} // namespace
TEST(HeapTest, GarbageCollectedInConstruction) {
MakeGarbageCollected<ObjectCheckingForInConstruction>();
}
TEST(HeapTest, GarbageCollectedMixinInConstruction) {
MakeGarbageCollected<MixinAppCheckingInConstruction>();
}
} // namespace blink
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