[K/N] Decouple ObjectFactory from concrete ObjectData ^KT-60928
* Use type_layout to declaratively express heap object headers in both
custom allocator and ObjectFactory.
* Invoke constructor (w/o invoking Kotin constructors) for created
objects and arrays from both custom allocator and ObjectFactory.
Previously:
- custom allocator only checked body for nullability (now this is
performed in body constructor)
- ObjectFactory only constructed ObjectData
* In each GC have a AllocatorImpl.hpp and ObjectData.hpp headers
the first encapsulating allocator-specific types, the second
containing specific ObjectData implementation.
* In each GC have a separate ObjectFactoryTraits that does not
actually depend on the specific GC anymore.
* Each GC now expose ObjectData (as undefined type) and its descriptor,
the latter being used by the custom allocator and ObjectFactory.
* Descriptors for ObjectBody and ArrayBody now live in Memory.h and the
code calculating size is now shared. Their constructors check that the
memory is zeroed (Kotlin constructors will expect this).
This commit is contained in:
committed by
Space Team
parent
d956a5504d
commit
83a70ddf8b
@@ -19,9 +19,11 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "Alignment.hpp"
|
||||
#include "KAssert.h"
|
||||
#include "Common.h"
|
||||
#include "TypeInfo.h"
|
||||
#include "TypeLayout.hpp"
|
||||
#include "Atomic.h"
|
||||
#include "PointerBits.h"
|
||||
#include "Utils.hpp"
|
||||
@@ -125,6 +127,7 @@ struct ObjHeader {
|
||||
static MetaObjHeader* createMetaObject(ObjHeader* object);
|
||||
static void destroyMetaObject(ObjHeader* object);
|
||||
};
|
||||
static_assert(alignof(ObjHeader) <= kotlin::kObjectAlignment);
|
||||
|
||||
// Header of value type array objects. Keep layout in sync with that of object header.
|
||||
struct ArrayHeader {
|
||||
@@ -140,6 +143,61 @@ struct ArrayHeader {
|
||||
// Elements count. Element size is stored in instanceSize_ field of TypeInfo, negated.
|
||||
uint32_t count_;
|
||||
};
|
||||
static_assert(alignof(ArrayHeader) <= kotlin::kObjectAlignment);
|
||||
|
||||
#ifndef KONAN_WASM
|
||||
namespace kotlin {
|
||||
|
||||
struct ObjectBody;
|
||||
struct ArrayBody;
|
||||
|
||||
template <>
|
||||
struct type_layout::descriptor<ObjectBody> {
|
||||
class type {
|
||||
public:
|
||||
using value_type = ObjectBody;
|
||||
|
||||
explicit type(const TypeInfo* typeInfo) noexcept : size_(typeInfo->instanceSize_ - sizeof(ObjHeader)) {}
|
||||
|
||||
static constexpr size_t alignment() noexcept { return kObjectAlignment; }
|
||||
uint64_t size() const noexcept { return size_; }
|
||||
|
||||
value_type* construct(uint8_t* ptr) noexcept {
|
||||
RuntimeAssert(isZeroed(std_support::span<uint8_t>(ptr, size_)), "ObjectBodyDescriptor::construct@%p memory is not zeroed", ptr);
|
||||
return reinterpret_cast<value_type*>(ptr);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t size_;
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct type_layout::descriptor<ArrayBody> {
|
||||
class type {
|
||||
public:
|
||||
using value_type = ArrayBody;
|
||||
|
||||
explicit type(const TypeInfo* typeInfo, uint32_t count) noexcept :
|
||||
// -(int32_t min) * uint32_t max cannot overflow uint64_t. And are capped
|
||||
// at about half of uint64_t max.
|
||||
size_(static_cast<uint64_t>(-typeInfo->instanceSize_) * count) {}
|
||||
|
||||
static constexpr size_t alignment() noexcept { return kObjectAlignment; }
|
||||
uint64_t size() const noexcept { return size_; }
|
||||
|
||||
value_type* construct(uint8_t* ptr) noexcept {
|
||||
RuntimeAssert(isZeroed(std_support::span<uint8_t>(ptr, size_)), "ArrayBodyDescriptor::construct@%p memory is not zeroed", ptr);
|
||||
return reinterpret_cast<ArrayBody*>(ptr);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t size_;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace kotlin
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE bool isPermanentOrFrozen(const ObjHeader* obj);
|
||||
ALWAYS_INLINE bool isShareable(const ObjHeader* obj);
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
using namespace kotlin;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -68,4 +71,10 @@ struct HashCompineImpl<64> {
|
||||
|
||||
size_t kotlin::CombineHash(size_t seed, size_t value) {
|
||||
return HashCompineImpl<sizeof(std::size_t) * CHAR_BIT>::fn(seed, value);
|
||||
}
|
||||
}
|
||||
|
||||
bool kotlin::isZeroed(std_support::span<uint8_t> span) noexcept {
|
||||
if (span.size() == 0) return true;
|
||||
if (span[0] != 0) return false;
|
||||
return memcmp(span.data(), span.data() + 1, span.size() - 1) == 0;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "std_support/Span.hpp"
|
||||
|
||||
namespace kotlin {
|
||||
|
||||
// A helper for implementing classes with disabled copy constructor and copy assignment.
|
||||
@@ -98,6 +100,9 @@ size_t CombineHash(size_t seed, size_t value);
|
||||
|
||||
#define ownerOf(type, field, ref) *reinterpret_cast<type*>(reinterpret_cast<char*>(&ref) - offsetof(type, field))
|
||||
|
||||
// Returns `true` if the entire `span` is zeroed.
|
||||
bool isZeroed(std_support::span<uint8_t> span) noexcept;
|
||||
|
||||
} // namespace kotlin
|
||||
|
||||
#endif // RUNTIME_UTILS_H
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
@@ -73,3 +74,26 @@ TEST(UtilsTest, OwnerOf) {
|
||||
EXPECT_THAT(&c, &Container::fromX(c.x()));
|
||||
EXPECT_THAT(&c, &Container::fromY(c.y()));
|
||||
}
|
||||
|
||||
TEST(UtilsTest, IsZeroed) {
|
||||
std::array<uint8_t, 0> empty;
|
||||
EXPECT_TRUE(isZeroed(empty));
|
||||
|
||||
std::array<uint8_t, 1> zeroed1 = {0};
|
||||
EXPECT_TRUE(isZeroed(zeroed1));
|
||||
|
||||
std::array<uint8_t, 1> notZeroed1 = {1};
|
||||
EXPECT_FALSE(isZeroed(notZeroed1));
|
||||
|
||||
std::array<uint8_t, 3> zeroed3 = {0, 0, 0};
|
||||
EXPECT_TRUE(isZeroed(zeroed3));
|
||||
|
||||
std::array<uint8_t, 3> notZeroed3_0 = {1, 0, 0};
|
||||
EXPECT_FALSE(isZeroed(notZeroed3_0));
|
||||
|
||||
std::array<uint8_t, 3> notZeroed3_1 = {0, 1, 0};
|
||||
EXPECT_FALSE(isZeroed(notZeroed3_1));
|
||||
|
||||
std::array<uint8_t, 3> notZeroed3_2 = {0, 0, 1};
|
||||
EXPECT_FALSE(isZeroed(notZeroed3_2));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user