Add MoveOnly and Pinned (#4526)

This commit is contained in:
Alexander Shabalin
2020-11-17 18:43:11 +03:00
committed by Stanislav Erokhin
parent 98b2f3feec
commit 0dfc99ab1a
13 changed files with 149 additions and 37 deletions
@@ -38,11 +38,12 @@
#include "Exceptions.h"
#include "ExecFormat.h"
#include "Memory.h"
#include "Mutex.hpp"
#include "Natives.h"
#include "KString.h"
#include "SourceInfo.h"
#include "Types.h"
#include "Utils.h"
#include "Utils.hpp"
#include "ObjCExceptions.h"
namespace {
@@ -279,7 +280,8 @@ RUNTIME_NORETURN void TerminateWithUnhandledException(KRef throwable) {
#if KONAN_HAS_CXX11_EXCEPTION_FUNCTIONS
namespace {
class TerminateHandler {
// Copy, move and assign would be safe, but not much useful, so let's delete all (rule of 5)
class TerminateHandler : private kotlin::Pinned {
// In fact, it's safe to call my_handler directly from outside: it will do the job and then invoke original handler,
// even if it has not been initialized yet. So one may want to make it public and/or not the class member
@@ -313,11 +315,6 @@ class TerminateHandler {
return singleton;
}
// Copy, move and assign would be safe, but not much useful, so let's delete all (rule of 5)
TerminateHandler(const TerminateHandler&) = delete;
TerminateHandler(TerminateHandler&&) = delete;
TerminateHandler& operator=(const TerminateHandler&) = delete;
TerminateHandler& operator=(TerminateHandler&&) = delete;
// Dtor might be in use to restore original handler. However, consequent install
// will not reconstruct handler anyway, so let's keep dtor deleted to avoid confusion.
~TerminateHandler() = delete;
@@ -14,8 +14,12 @@
* limitations under the License.
*/
#ifndef RUNTIME_MUTEX_H
#define RUNTIME_MUTEX_H
#include <cstdint>
#include "KAssert.h"
#include "Utils.hpp"
class SimpleMutex {
private:
@@ -37,7 +41,7 @@ class SimpleMutex {
// TODO: use std::lock_guard instead?
template <class Mutex>
class LockGuard {
class LockGuard : private kotlin::Pinned {
public:
explicit LockGuard(Mutex& mutex_) : mutex(mutex_) {
mutex.lock();
@@ -49,7 +53,6 @@ class LockGuard {
private:
Mutex& mutex;
LockGuard(const LockGuard&) = delete;
LockGuard& operator=(const LockGuard&) = delete;
};
#endif // RUNTIME_MUTEX_H
@@ -39,7 +39,7 @@
#import "ObjCExportPrivate.h"
#import "ObjCMMAPI.h"
#import "Runtime.h"
#import "Utils.h"
#import "Mutex.hpp"
#import "Exceptions.h"
struct ObjCToKotlinMethodAdapter {
@@ -24,7 +24,7 @@
#import "ObjCExport.h"
#import "Porting.h"
#import "Runtime.h"
#import "Utils.h"
#import "Mutex.hpp"
#import "ObjCExportErrors.h"
@@ -33,7 +33,7 @@
#include "ObjCExportPrivate.h"
#include "ObjCMMAPI.h"
#include "Types.h"
#include "Utils.h"
#include "Mutex.hpp"
// Replaced in ObjCExportCodeGenerator.
__attribute__((weak)) const char* Kotlin_ObjCInterop_uniquePrefix = nullptr;
@@ -7,22 +7,18 @@
#define RUNTIME_OBJCMMAPI_H
#include "Common.h"
#include "Utils.hpp"
#if KONAN_OBJC_INTEROP
extern "C" ALWAYS_INLINE void Kotlin_ObjCExport_releaseAssociatedObject(void* associatedObject);
namespace konan {
class AutoreleasePool {
class AutoreleasePool : private kotlin::Pinned {
public:
AutoreleasePool();
~AutoreleasePool();
AutoreleasePool(const AutoreleasePool&) = delete;
AutoreleasePool(AutoreleasePool&&) = delete;
AutoreleasePool& operator=(const AutoreleasePool&) = delete;
AutoreleasePool& operator=(AutoreleasePool&&) = delete;
private:
void* handle;
};
@@ -10,9 +10,10 @@
#include "gtest/gtest.h"
#include "Types.h"
#include "Utils.hpp"
template <class F>
class ScopedStrictMockFunction {
class ScopedStrictMockFunction : private kotlin::MoveOnly {
public:
using Mock = testing::StrictMock<testing::MockFunction<F>>;
@@ -24,9 +25,6 @@ public:
*globalMockLocation_ = mock_.get();
}
ScopedStrictMockFunction(const ScopedStrictMockFunction&) = delete;
ScopedStrictMockFunction& operator=(const ScopedStrictMockFunction&) = delete;
ScopedStrictMockFunction(ScopedStrictMockFunction&& rhs) : globalMockLocation_(rhs.globalMockLocation_), mock_(std::move(rhs.mock_)) {
rhs.globalMockLocation_ = nullptr;
}
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_UTILS_H
#define RUNTIME_UTILS_H
namespace kotlin {
// A helper for implementing classes with disabled copy constructor and copy assignment.
// Usage:
// class A: private MoveOnly {
// ...
// };
// Prefer private inheritance to discourage casting instances of `A` to instances
// of `MoveOnly`.
class MoveOnly {
// Hide constructors, assignments and destructor, to discourage operating on an instance of `MoveOnly`.
protected:
MoveOnly() noexcept = default;
MoveOnly(const MoveOnly&) = delete;
MoveOnly(MoveOnly&&) noexcept = default;
MoveOnly& operator=(const MoveOnly&) = delete;
MoveOnly& operator=(MoveOnly&&) noexcept = default;
// Not virtual by design. Since this class hides this destructor, no one can destroy an
// instance of `MoveOnly` directly, so this destructor is never called in a virtual manner.
~MoveOnly() = default;
};
// A helper for implementing classes with disabled copy and move constructors, and copy and move assignments.
// Usage:
// class A: private Pinned {
// ...
// };
// Prefer private inheritance to discourage casting instances of `A` to instances
// of `Pinned`.
class Pinned {
// Hide constructors, assignments and destructor, to discourage operating on an instance of `Pinned`.
protected:
Pinned() noexcept = default;
Pinned(const Pinned&) = delete;
Pinned(Pinned&&) = delete;
Pinned& operator=(const Pinned&) = delete;
Pinned& operator=(Pinned&&) = delete;
// Not virtual by design. Since this class hides this destructor, no one can destroy an
// instance of `Pinned` directly, so this destructor is never called in a virtual manner.
~Pinned() = default;
};
} // namespace kotlin
#endif // RUNTIME_UTILS_H
@@ -0,0 +1,66 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include "Utils.hpp"
#include <type_traits>
#include "gtest/gtest.h"
namespace {
// TODO: use std variants when we move to C++17
template <typename T>
constexpr bool is_nothrow_default_constructible_v = std::is_nothrow_default_constructible<T>::value;
template <typename T>
constexpr bool is_nothrow_destructible_v = std::is_nothrow_destructible<T>::value;
template <typename T>
constexpr bool is_copy_constructible_v = std::is_copy_constructible<T>::value;
template <typename T>
constexpr bool is_copy_assignable_v = std::is_copy_assignable<T>::value;
template <typename T>
constexpr bool is_move_constructible_v = std::is_move_constructible<T>::value;
template <typename T>
constexpr bool is_move_assignable_v = std::is_move_assignable<T>::value;
template <typename T>
constexpr bool is_nothrow_move_constructible_v = std::is_nothrow_move_constructible<T>::value;
template <typename T>
constexpr bool is_nothrow_move_assignable_v = std::is_nothrow_move_assignable<T>::value;
struct A {
int field;
};
class MoveOnlyImpl : private kotlin::MoveOnly {
public:
A a;
};
class PinnedImpl : private kotlin::Pinned {
public:
A a;
};
} // namespace
TEST(UtilsTest, MoveOnlyImpl) {
static_assert(is_nothrow_default_constructible_v<MoveOnlyImpl>, "Must be nothrow default constructible");
static_assert(is_nothrow_destructible_v<MoveOnlyImpl>, "Must be nothrow destructible");
static_assert(!is_copy_constructible_v<MoveOnlyImpl>, "Must not be copy constructible");
static_assert(!is_copy_assignable_v<MoveOnlyImpl>, "Must not be copy assignable");
static_assert(is_nothrow_move_constructible_v<MoveOnlyImpl>, "Must be nothrow move constructible");
static_assert(is_nothrow_move_assignable_v<MoveOnlyImpl>, "Must be nothrow move assignable");
static_assert(sizeof(MoveOnlyImpl) == sizeof(A), "Must not increase size");
}
TEST(UtilsTest, PinnedImpl) {
static_assert(is_nothrow_default_constructible_v<PinnedImpl>, "Must be nothrow default constructible");
static_assert(is_nothrow_destructible_v<PinnedImpl>, "Must be nothrow destructible");
static_assert(!is_copy_constructible_v<PinnedImpl>, "Must not be copy constructible");
static_assert(!is_copy_assignable_v<PinnedImpl>, "Must not be copy assignable");
static_assert(!is_move_constructible_v<PinnedImpl>, "Must not be move constructible");
static_assert(!is_move_assignable_v<PinnedImpl>, "Must not be move assignable");
static_assert(sizeof(PinnedImpl) == sizeof(A), "Must not increase size");
}