Add MoveOnly and Pinned (#4526)
This commit is contained in:
committed by
Stanislav Erokhin
parent
98b2f3feec
commit
0dfc99ab1a
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
* Headers should live in the same folder with it's implementation counterpart (if there's one) **TODO**: This does not work with multiple implementations of a single header.
|
* Headers should live in the same folder with it's implementation counterpart (if there's one) **TODO**: This does not work with multiple implementations of a single header.
|
||||||
* Headers should use header guards
|
* Headers should use header guards
|
||||||
|
* Headers that are designed to be included into both `.cpp`/`.mm` and `.c`/`.m` should have extension `.h`
|
||||||
|
* Headers that are designed to be included into `.cpp`/`.mm` only should have extension `.hpp`
|
||||||
|
|
||||||
## Namespace usage
|
## Namespace usage
|
||||||
|
|
||||||
|
|||||||
@@ -41,10 +41,11 @@
|
|||||||
#include "KString.h"
|
#include "KString.h"
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "MemoryPrivate.hpp"
|
#include "MemoryPrivate.hpp"
|
||||||
|
#include "Mutex.hpp"
|
||||||
#include "Natives.h"
|
#include "Natives.h"
|
||||||
#include "Porting.h"
|
#include "Porting.h"
|
||||||
#include "Runtime.h"
|
#include "Runtime.h"
|
||||||
#include "Utils.h"
|
#include "Utils.hpp"
|
||||||
#include "WorkerBoundReference.h"
|
#include "WorkerBoundReference.h"
|
||||||
#include "Weak.h"
|
#include "Weak.h"
|
||||||
|
|
||||||
@@ -150,20 +151,16 @@ KBoolean g_hasCyclicCollector = true;
|
|||||||
#endif // USE_CYCLIC_GC
|
#endif // USE_CYCLIC_GC
|
||||||
|
|
||||||
// TODO: Consider using ObjHolder.
|
// TODO: Consider using ObjHolder.
|
||||||
class ScopedRefHolder {
|
class ScopedRefHolder : private kotlin::MoveOnly {
|
||||||
public:
|
public:
|
||||||
ScopedRefHolder() = default;
|
ScopedRefHolder() = default;
|
||||||
|
|
||||||
explicit ScopedRefHolder(KRef obj);
|
explicit ScopedRefHolder(KRef obj);
|
||||||
|
|
||||||
ScopedRefHolder(const ScopedRefHolder&) = delete;
|
|
||||||
|
|
||||||
ScopedRefHolder(ScopedRefHolder&& other) noexcept: obj_(other.obj_) {
|
ScopedRefHolder(ScopedRefHolder&& other) noexcept: obj_(other.obj_) {
|
||||||
other.obj_ = nullptr;
|
other.obj_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedRefHolder& operator=(const ScopedRefHolder&) = delete;
|
|
||||||
|
|
||||||
ScopedRefHolder& operator=(ScopedRefHolder&& other) noexcept {
|
ScopedRefHolder& operator=(ScopedRefHolder&& other) noexcept {
|
||||||
ScopedRefHolder tmp(std::move(other));
|
ScopedRefHolder tmp(std::move(other));
|
||||||
swap(tmp);
|
swap(tmp);
|
||||||
@@ -191,7 +188,7 @@ struct CycleDetectorRootset {
|
|||||||
KStdVector<ScopedRefHolder> heldRefs;
|
KStdVector<ScopedRefHolder> heldRefs;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CycleDetector {
|
class CycleDetector : private kotlin::Pinned {
|
||||||
public:
|
public:
|
||||||
static void insertCandidateIfNeeded(KRef object) {
|
static void insertCandidateIfNeeded(KRef object) {
|
||||||
if (canBeACandidate(object))
|
if (canBeACandidate(object))
|
||||||
@@ -208,10 +205,6 @@ class CycleDetector {
|
|||||||
private:
|
private:
|
||||||
CycleDetector() = default;
|
CycleDetector() = default;
|
||||||
~CycleDetector() = default;
|
~CycleDetector() = default;
|
||||||
CycleDetector(const CycleDetector&) = delete;
|
|
||||||
CycleDetector(CycleDetector&&) = delete;
|
|
||||||
CycleDetector& operator=(const CycleDetector&) = delete;
|
|
||||||
CycleDetector& operator=(CycleDetector&&) = delete;
|
|
||||||
|
|
||||||
static CycleDetector& instance() {
|
static CycleDetector& instance() {
|
||||||
// Only store a pointer to CycleDetector in .bss
|
// Only store a pointer to CycleDetector in .bss
|
||||||
|
|||||||
@@ -38,11 +38,12 @@
|
|||||||
#include "Exceptions.h"
|
#include "Exceptions.h"
|
||||||
#include "ExecFormat.h"
|
#include "ExecFormat.h"
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
|
#include "Mutex.hpp"
|
||||||
#include "Natives.h"
|
#include "Natives.h"
|
||||||
#include "KString.h"
|
#include "KString.h"
|
||||||
#include "SourceInfo.h"
|
#include "SourceInfo.h"
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
#include "Utils.h"
|
#include "Utils.hpp"
|
||||||
#include "ObjCExceptions.h"
|
#include "ObjCExceptions.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -279,7 +280,8 @@ RUNTIME_NORETURN void TerminateWithUnhandledException(KRef throwable) {
|
|||||||
#if KONAN_HAS_CXX11_EXCEPTION_FUNCTIONS
|
#if KONAN_HAS_CXX11_EXCEPTION_FUNCTIONS
|
||||||
|
|
||||||
namespace {
|
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,
|
// 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
|
// 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;
|
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
|
// 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.
|
// will not reconstruct handler anyway, so let's keep dtor deleted to avoid confusion.
|
||||||
~TerminateHandler() = delete;
|
~TerminateHandler() = delete;
|
||||||
|
|||||||
+7
-4
@@ -14,8 +14,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef RUNTIME_MUTEX_H
|
||||||
|
#define RUNTIME_MUTEX_H
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "KAssert.h"
|
#include "KAssert.h"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
class SimpleMutex {
|
class SimpleMutex {
|
||||||
private:
|
private:
|
||||||
@@ -37,7 +41,7 @@ class SimpleMutex {
|
|||||||
|
|
||||||
// TODO: use std::lock_guard instead?
|
// TODO: use std::lock_guard instead?
|
||||||
template <class Mutex>
|
template <class Mutex>
|
||||||
class LockGuard {
|
class LockGuard : private kotlin::Pinned {
|
||||||
public:
|
public:
|
||||||
explicit LockGuard(Mutex& mutex_) : mutex(mutex_) {
|
explicit LockGuard(Mutex& mutex_) : mutex(mutex_) {
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
@@ -49,7 +53,6 @@ class LockGuard {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Mutex& mutex;
|
Mutex& mutex;
|
||||||
|
|
||||||
LockGuard(const LockGuard&) = delete;
|
|
||||||
LockGuard& operator=(const LockGuard&) = delete;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // RUNTIME_MUTEX_H
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
#import "ObjCExportPrivate.h"
|
#import "ObjCExportPrivate.h"
|
||||||
#import "ObjCMMAPI.h"
|
#import "ObjCMMAPI.h"
|
||||||
#import "Runtime.h"
|
#import "Runtime.h"
|
||||||
#import "Utils.h"
|
#import "Mutex.hpp"
|
||||||
#import "Exceptions.h"
|
#import "Exceptions.h"
|
||||||
|
|
||||||
struct ObjCToKotlinMethodAdapter {
|
struct ObjCToKotlinMethodAdapter {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
#import "ObjCExport.h"
|
#import "ObjCExport.h"
|
||||||
#import "Porting.h"
|
#import "Porting.h"
|
||||||
#import "Runtime.h"
|
#import "Runtime.h"
|
||||||
#import "Utils.h"
|
#import "Mutex.hpp"
|
||||||
|
|
||||||
#import "ObjCExportErrors.h"
|
#import "ObjCExportErrors.h"
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
#include "ObjCExportPrivate.h"
|
#include "ObjCExportPrivate.h"
|
||||||
#include "ObjCMMAPI.h"
|
#include "ObjCMMAPI.h"
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
#include "Utils.h"
|
#include "Mutex.hpp"
|
||||||
|
|
||||||
// Replaced in ObjCExportCodeGenerator.
|
// Replaced in ObjCExportCodeGenerator.
|
||||||
__attribute__((weak)) const char* Kotlin_ObjCInterop_uniquePrefix = nullptr;
|
__attribute__((weak)) const char* Kotlin_ObjCInterop_uniquePrefix = nullptr;
|
||||||
|
|||||||
@@ -7,22 +7,18 @@
|
|||||||
#define RUNTIME_OBJCMMAPI_H
|
#define RUNTIME_OBJCMMAPI_H
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
#if KONAN_OBJC_INTEROP
|
#if KONAN_OBJC_INTEROP
|
||||||
|
|
||||||
extern "C" ALWAYS_INLINE void Kotlin_ObjCExport_releaseAssociatedObject(void* associatedObject);
|
extern "C" ALWAYS_INLINE void Kotlin_ObjCExport_releaseAssociatedObject(void* associatedObject);
|
||||||
|
|
||||||
namespace konan {
|
namespace konan {
|
||||||
class AutoreleasePool {
|
class AutoreleasePool : private kotlin::Pinned {
|
||||||
public:
|
public:
|
||||||
AutoreleasePool();
|
AutoreleasePool();
|
||||||
~AutoreleasePool();
|
~AutoreleasePool();
|
||||||
|
|
||||||
AutoreleasePool(const AutoreleasePool&) = delete;
|
|
||||||
AutoreleasePool(AutoreleasePool&&) = delete;
|
|
||||||
AutoreleasePool& operator=(const AutoreleasePool&) = delete;
|
|
||||||
AutoreleasePool& operator=(AutoreleasePool&&) = delete;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void* handle;
|
void* handle;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,9 +10,10 @@
|
|||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
template <class F>
|
template <class F>
|
||||||
class ScopedStrictMockFunction {
|
class ScopedStrictMockFunction : private kotlin::MoveOnly {
|
||||||
public:
|
public:
|
||||||
using Mock = testing::StrictMock<testing::MockFunction<F>>;
|
using Mock = testing::StrictMock<testing::MockFunction<F>>;
|
||||||
|
|
||||||
@@ -24,9 +25,6 @@ public:
|
|||||||
*globalMockLocation_ = mock_.get();
|
*globalMockLocation_ = mock_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedStrictMockFunction(const ScopedStrictMockFunction&) = delete;
|
|
||||||
ScopedStrictMockFunction& operator=(const ScopedStrictMockFunction&) = delete;
|
|
||||||
|
|
||||||
ScopedStrictMockFunction(ScopedStrictMockFunction&& rhs) : globalMockLocation_(rhs.globalMockLocation_), mock_(std::move(rhs.mock_)) {
|
ScopedStrictMockFunction(ScopedStrictMockFunction&& rhs) : globalMockLocation_(rhs.globalMockLocation_), mock_(std::move(rhs.mock_)) {
|
||||||
rhs.globalMockLocation_ = nullptr;
|
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");
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
#import "ObjCExportInit.h"
|
#import "ObjCExportInit.h"
|
||||||
#import "ObjCExportPrivate.h"
|
#import "ObjCExportPrivate.h"
|
||||||
#import "Runtime.h"
|
#import "Runtime.h"
|
||||||
#import "Utils.h"
|
#import "Mutex.hpp"
|
||||||
#import "Exceptions.h"
|
#import "Exceptions.h"
|
||||||
|
|
||||||
extern "C" id objc_retainAutoreleaseReturnValue(id self);
|
extern "C" id objc_retainAutoreleaseReturnValue(id self);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#import "ObjCExport.h"
|
#import "ObjCExport.h"
|
||||||
#import "Runtime.h"
|
#import "Runtime.h"
|
||||||
#import "Utils.h"
|
#import "Mutex.hpp"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user