Keep MemoryState empty. (#4544)
This commit is contained in:
committed by
Stanislav Erokhin
parent
e548bde89f
commit
83de4e174a
@@ -44,8 +44,6 @@ template <typename T>
|
|||||||
constexpr bool is_nothrow_move_constructible_v = std::is_nothrow_move_constructible<T>::value;
|
constexpr bool is_nothrow_move_constructible_v = std::is_nothrow_move_constructible<T>::value;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr bool is_nothrow_move_assignable_v = std::is_nothrow_move_assignable<T>::value;
|
constexpr bool is_nothrow_move_assignable_v = std::is_nothrow_move_assignable<T>::value;
|
||||||
template <typename T>
|
|
||||||
constexpr bool is_standard_layout_v = std::is_standard_layout<T>::value;
|
|
||||||
|
|
||||||
} // namespace std_support
|
} // namespace std_support
|
||||||
} // namespace kotlin
|
} // namespace kotlin
|
||||||
|
|||||||
@@ -54,25 +54,6 @@ protected:
|
|||||||
~Pinned() = default;
|
~Pinned() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Given
|
|
||||||
// struct SomeWrapper {
|
|
||||||
// SomeType value;
|
|
||||||
// ... // (possibly) some other fields
|
|
||||||
// };
|
|
||||||
// allows to cast from `SomeValue*` to `SomeWrapper*` as no-op. It only works
|
|
||||||
// if `SomeWrapper` is standard layout and `value` is the first non-static data member.
|
|
||||||
// See https://en.cppreference.com/w/cpp/language/data_members#Standard_layout
|
|
||||||
//
|
|
||||||
// Useful for exporting SomeType under a different name (e.g. exporting inner C++ class
|
|
||||||
// as public C struct).
|
|
||||||
#define wrapper_cast(Wrapper, inner, field) \
|
|
||||||
/* With -O2 the lambda is replaced with a cast in the bitcode. */ \
|
|
||||||
[inner]() { \
|
|
||||||
static_assert(std_support::is_standard_layout_v<Wrapper>, #Wrapper " must be standard layout"); \
|
|
||||||
static_assert(offsetof(Wrapper, field) == 0, #field " must be at 0 offset"); \
|
|
||||||
return reinterpret_cast<Wrapper*>(inner); \
|
|
||||||
}()
|
|
||||||
|
|
||||||
} // namespace kotlin
|
} // namespace kotlin
|
||||||
|
|
||||||
#endif // RUNTIME_UTILS_H
|
#endif // RUNTIME_UTILS_H
|
||||||
|
|||||||
@@ -48,27 +48,3 @@ TEST(UtilsTest, PinnedImpl) {
|
|||||||
static_assert(!std_support::is_move_assignable_v<PinnedImpl>, "Must not be move assignable");
|
static_assert(!std_support::is_move_assignable_v<PinnedImpl>, "Must not be move assignable");
|
||||||
static_assert(sizeof(PinnedImpl) == sizeof(A), "Must not increase size");
|
static_assert(sizeof(PinnedImpl) == sizeof(A), "Must not increase size");
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct Wrapper {
|
|
||||||
A wrapped;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WrapperOverPinned {
|
|
||||||
PinnedImpl wrapped;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
TEST(UtilsTest, WrapperCast) {
|
|
||||||
A value;
|
|
||||||
Wrapper* wrapper = wrapper_cast(Wrapper, &value, wrapped);
|
|
||||||
EXPECT_EQ(&value, &wrapper->wrapped);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(UtilsTest, WrapperOverPinnedCast) {
|
|
||||||
PinnedImpl value;
|
|
||||||
WrapperOverPinned* wrapper = wrapper_cast(WrapperOverPinned, &value, wrapped);
|
|
||||||
EXPECT_EQ(&value, &wrapper->wrapped);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,19 +11,23 @@
|
|||||||
|
|
||||||
using namespace kotlin;
|
using namespace kotlin;
|
||||||
|
|
||||||
extern "C" struct MemoryState {
|
// Delete all means of creating this type directly as it only serves
|
||||||
mm::ThreadRegistry::Node data;
|
// as a typedef for `mm::ThreadRegistry::Node`.
|
||||||
// Do not add any other fields: this struct is just a wrapper around ThreadDataNode.
|
extern "C" struct MemoryState : Pinned {
|
||||||
|
MemoryState() = delete;
|
||||||
|
~MemoryState() = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// `reinterpret_cast` to it and back to the same type
|
||||||
|
// will yield precisely the same pointer, so it's safe.
|
||||||
ALWAYS_INLINE MemoryState* ToMemoryState(mm::ThreadRegistry::Node* data) {
|
ALWAYS_INLINE MemoryState* ToMemoryState(mm::ThreadRegistry::Node* data) {
|
||||||
return wrapper_cast(MemoryState, data, data);
|
return reinterpret_cast<MemoryState*>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE mm::ThreadRegistry::Node* FromMemoryState(MemoryState* state) {
|
ALWAYS_INLINE mm::ThreadRegistry::Node* FromMemoryState(MemoryState* state) {
|
||||||
return &state->data;
|
return reinterpret_cast<mm::ThreadRegistry::Node*>(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
Reference in New Issue
Block a user