[K/N] Rework allocating of ExtraObjectData objects.
^KT-49325
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include "FinalizerHooksTestSupport.hpp"
|
||||
#include "Memory.h"
|
||||
#include "ObjectTestSupport.hpp"
|
||||
#include "TestSupport.hpp"
|
||||
|
||||
using namespace kotlin;
|
||||
|
||||
@@ -46,6 +47,7 @@ TEST_F(FinalizerHooksTest, TypeWithFinalizerHookWithoutExtra) {
|
||||
}
|
||||
|
||||
TEST_F(FinalizerHooksTest, TypeWithFinalizerHookWithExtra) {
|
||||
ScopedMemoryInit init;
|
||||
test_support::TypeInfoHolder type{test_support::TypeInfoHolder::ObjectBuilder<EmptyPayload>().addFlag(TF_HAS_FINALIZER)};
|
||||
test_support::Object<EmptyPayload> object(type.typeInfo());
|
||||
ObjHeader* obj = object.header();
|
||||
@@ -71,6 +73,7 @@ TEST_F(FinalizerHooksTest, TypeWithoutFinalizerHookWithoutExtra) {
|
||||
}
|
||||
|
||||
TEST_F(FinalizerHooksTest, TypeWithoutFinalizerHookWithExtra) {
|
||||
ScopedMemoryInit init;
|
||||
test_support::TypeInfoHolder type{test_support::TypeInfoHolder::ObjectBuilder<EmptyPayload>()};
|
||||
test_support::Object<EmptyPayload> object(type.typeInfo());
|
||||
ObjHeader* obj = object.header();
|
||||
|
||||
@@ -25,10 +25,18 @@ public:
|
||||
// and to not store the iterator.
|
||||
class Node : private Pinned, public KonanAllocatorAware {
|
||||
public:
|
||||
Node(const T& value, Producer* owner) noexcept : value_(value), owner_(owner) {}
|
||||
Node(Producer* owner, const T& value) noexcept : value_(value), owner_(owner) {}
|
||||
|
||||
template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
|
||||
explicit Node(Producer* owner, Args&& ...args) noexcept : value_(std::forward<Args>(args)...), owner_(owner) {}
|
||||
|
||||
T& operator*() noexcept { return value_; }
|
||||
|
||||
static Node& fromValue(T& t) noexcept {
|
||||
static_assert(std::is_base_of_v<Pinned, T>, "fromValue function only makes sense for non-movable object");
|
||||
return *reinterpret_cast<Node*>(reinterpret_cast<uintptr_t>(&t) - offsetof(Node, value_));
|
||||
}
|
||||
|
||||
private:
|
||||
friend class MultiSourceQueue;
|
||||
|
||||
@@ -44,7 +52,15 @@ public:
|
||||
~Producer() { Publish(); }
|
||||
|
||||
Node* Insert(const T& value) noexcept {
|
||||
queue_.emplace_back(value, this);
|
||||
queue_.emplace_back(this, value);
|
||||
auto& node = queue_.back();
|
||||
node.position_ = std::prev(queue_.end());
|
||||
return &node;
|
||||
}
|
||||
|
||||
template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
|
||||
Node* Emplace(Args&& ...value) noexcept {
|
||||
queue_.emplace_back(this, std::forward<Args>(value)...);
|
||||
auto& node = queue_.back();
|
||||
node.position_ = std::prev(queue_.end());
|
||||
return &node;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "ObjectOps.hpp"
|
||||
#include "PointerBits.h"
|
||||
#include "Weak.h"
|
||||
#include "ExtraObjectDataFactory.hpp"
|
||||
|
||||
#ifdef KONAN_OBJC_INTEROP
|
||||
#include "ObjCMMAPI.h"
|
||||
@@ -42,16 +43,17 @@ mm::ExtraObjectData& mm::ExtraObjectData::Install(ObjHeader* object) noexcept {
|
||||
|
||||
RuntimeCheck(!hasPointerBits(typeInfo, OBJECT_TAG_MASK), "Object must not be tagged");
|
||||
|
||||
auto* data = new ExtraObjectData(typeInfo);
|
||||
auto *threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
|
||||
auto& data = mm::ExtraObjectDataFactory::Instance().CreateExtraObjectDataForObject(threadData, typeInfo);
|
||||
|
||||
TypeInfo* old = __sync_val_compare_and_swap(&object->typeInfoOrMeta_, typeInfo, reinterpret_cast<TypeInfo*>(data));
|
||||
TypeInfo* old = __sync_val_compare_and_swap(&object->typeInfoOrMeta_, typeInfo, reinterpret_cast<TypeInfo*>(&data));
|
||||
if (old != typeInfo) {
|
||||
// Somebody else created `mm::ExtraObjectData` for this object
|
||||
delete data;
|
||||
mm::ExtraObjectDataFactory::Instance().DestroyExtraObjectData(threadData, data);
|
||||
return *reinterpret_cast<mm::ExtraObjectData*>(old);
|
||||
}
|
||||
|
||||
return *data;
|
||||
return data;
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -62,7 +64,12 @@ void mm::ExtraObjectData::Uninstall(ObjHeader* object) noexcept {
|
||||
|
||||
*const_cast<const TypeInfo**>(&object->typeInfoOrMeta_) = data.typeInfo_;
|
||||
|
||||
delete &data;
|
||||
auto *threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
|
||||
#ifdef KONAN_OBJC_INTEROP
|
||||
Kotlin_ObjCExport_releaseAssociatedObject(data.associatedObject_);
|
||||
data.associatedObject_ = nullptr;
|
||||
#endif
|
||||
mm::ExtraObjectDataFactory::Instance().DestroyExtraObjectData(threadData, data);
|
||||
}
|
||||
|
||||
void mm::ExtraObjectData::DetachAssociatedObject() noexcept {
|
||||
@@ -89,6 +96,6 @@ mm::ExtraObjectData::~ExtraObjectData() {
|
||||
RuntimeAssert(!HasWeakReferenceCounter(), "Object must have cleared weak references");
|
||||
|
||||
#ifdef KONAN_OBJC_INTEROP
|
||||
Kotlin_ObjCExport_releaseAssociatedObject(associatedObject_);
|
||||
RuntimeAssert(associatedObject_ == nullptr, "Object must have cleared associated object");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "Memory.h"
|
||||
#include "TypeInfo.h"
|
||||
#include "Utils.hpp"
|
||||
#include "MultiSourceQueue.hpp"
|
||||
|
||||
namespace kotlin {
|
||||
namespace mm {
|
||||
@@ -51,9 +52,9 @@ public:
|
||||
bool HasWeakReferenceCounter() noexcept;
|
||||
void ClearWeakReferenceCounter() noexcept;
|
||||
|
||||
private:
|
||||
explicit ExtraObjectData(const TypeInfo* typeInfo) noexcept : typeInfo_(typeInfo) {}
|
||||
~ExtraObjectData();
|
||||
private:
|
||||
|
||||
// Must be first to match `TypeInfo` layout.
|
||||
const TypeInfo* typeInfo_;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 "ExtraObjectDataFactory.hpp"
|
||||
|
||||
#include "GlobalData.hpp"
|
||||
#include "ThreadData.hpp"
|
||||
|
||||
using namespace kotlin;
|
||||
|
||||
// static
|
||||
mm::ExtraObjectDataFactory& mm::ExtraObjectDataFactory::Instance() noexcept {
|
||||
return GlobalData::Instance().extraObjectDataFactory();
|
||||
}
|
||||
|
||||
mm::ExtraObjectData& mm::ExtraObjectDataFactory::CreateExtraObjectDataForObject(mm::ThreadData* threadData, TypeInfo* info) noexcept {
|
||||
return **threadData->extraObjectDataThreadQueue().Emplace(info);
|
||||
}
|
||||
|
||||
void mm::ExtraObjectDataFactory::DestroyExtraObjectData(mm::ThreadData* threadData, ExtraObjectData& data) noexcept {
|
||||
threadData->extraObjectDataThreadQueue().Erase(&Queue::Node::fromValue(data));
|
||||
}
|
||||
|
||||
void mm::ExtraObjectDataFactory::ProcessThread(mm::ThreadData* threadData) noexcept {
|
||||
threadData->extraObjectDataThreadQueue().Publish();
|
||||
}
|
||||
|
||||
void mm::ExtraObjectDataFactory::ProcessDeletions() noexcept {
|
||||
extraObjects_.ApplyDeletions();
|
||||
}
|
||||
|
||||
mm::ExtraObjectDataFactory::ExtraObjectDataFactory() = default;
|
||||
mm::ExtraObjectDataFactory::~ExtraObjectDataFactory() = default;
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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_MM_EXTRA_OBJECT_DATA_REGISTRY_H
|
||||
#define RUNTIME_MM_EXTRA_OBJECT_DATA_REGISTRY_H
|
||||
|
||||
#include "Memory.h"
|
||||
#include "MultiSourceQueue.hpp"
|
||||
#include "ThreadRegistry.hpp"
|
||||
#include "ExtraObjectData.hpp"
|
||||
|
||||
namespace kotlin {
|
||||
namespace mm {
|
||||
|
||||
// Registry for extra data, attached to some kotlin objects: weak refs, associated objects, ...
|
||||
class ExtraObjectDataFactory : Pinned {
|
||||
using Mutex = SpinLock<MutexThreadStateHandling::kIgnore>;
|
||||
using Queue = MultiSourceQueue<mm::ExtraObjectData, Mutex>;
|
||||
public:
|
||||
class ThreadQueue : public Queue::Producer {
|
||||
public:
|
||||
explicit ThreadQueue(ExtraObjectDataFactory& registry) : Producer(registry.extraObjects_) {}
|
||||
// Do not add fields as this is just a wrapper and Producer does not have virtual destructor.
|
||||
};
|
||||
|
||||
using Iterable = Queue::Iterable;
|
||||
using Iterator = Queue::Iterator;
|
||||
|
||||
ExtraObjectDataFactory();
|
||||
~ExtraObjectDataFactory();
|
||||
|
||||
static ExtraObjectDataFactory& Instance() noexcept;
|
||||
|
||||
ExtraObjectData& CreateExtraObjectDataForObject(mm::ThreadData* threadData, TypeInfo* info) noexcept;
|
||||
|
||||
void DestroyExtraObjectData(mm::ThreadData* threadData, ExtraObjectData& data) noexcept;
|
||||
|
||||
// Collect extra data objects from thread corresponding to `threadData`. Must be called by the thread
|
||||
// when it's asked by GC to stop.
|
||||
void ProcessThread(mm::ThreadData* threadData) noexcept;
|
||||
|
||||
// Lock registry and apply deletions. Should be called on GC thread after all threads have published, and before `LockForIter`.
|
||||
void ProcessDeletions() noexcept;
|
||||
|
||||
// Lock registry for safe iteration.
|
||||
Iterable LockForIter() noexcept { return extraObjects_.LockForIter(); }
|
||||
|
||||
void ClearForTests() noexcept { extraObjects_.ClearForTests(); }
|
||||
|
||||
private:
|
||||
Queue extraObjects_;
|
||||
};
|
||||
|
||||
} // namespace mm
|
||||
} // namespace kotlin
|
||||
|
||||
#endif // RUNTIME_MM_EXTRA_OBJECT_DATA_REGISTRY_H
|
||||
@@ -26,6 +26,7 @@ struct EmptyPayload {
|
||||
} // namespace
|
||||
|
||||
TEST(ExtraObjectDataTest, Install) {
|
||||
ScopedMemoryInit init;
|
||||
test_support::TypeInfoHolder type{test_support::TypeInfoHolder::ObjectBuilder<EmptyPayload>()};
|
||||
test_support::Object<EmptyPayload> object(type.typeInfo());
|
||||
auto* typeInfo = object.header()->type_info();
|
||||
@@ -45,6 +46,7 @@ TEST(ExtraObjectDataTest, Install) {
|
||||
}
|
||||
|
||||
TEST(ExtraObjectDataTest, ConcurrentInstall) {
|
||||
ScopedMemoryInit init;
|
||||
test_support::TypeInfoHolder type{test_support::TypeInfoHolder::ObjectBuilder<EmptyPayload>()};
|
||||
test_support::Object<EmptyPayload> object(type.typeInfo());
|
||||
|
||||
@@ -57,6 +59,7 @@ TEST(ExtraObjectDataTest, ConcurrentInstall) {
|
||||
|
||||
for (int i = 0; i < kThreadCount; ++i) {
|
||||
threads.emplace_back([i, &actual, &object, &canStart, &readyCount]() {
|
||||
ScopedMemoryInit init;
|
||||
++readyCount;
|
||||
while (!canStart) {
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "Memory.h"
|
||||
#include "ObjectTestSupport.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "TestSupport.hpp"
|
||||
|
||||
using namespace kotlin;
|
||||
|
||||
@@ -153,6 +154,7 @@ TYPED_TEST(FreezingEmptyNoHookTest, PermanentIsFrozen) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingEmptyNoHookTest, FailToEnsureNeverFrozen) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
ASSERT_THAT(mm::FreezeSubgraph(object.header()), nullptr);
|
||||
ASSERT_TRUE(mm::IsFrozen(object.header()));
|
||||
@@ -167,12 +169,14 @@ TYPED_TEST(FreezingEmptyNoHookTest, FailToEnsureNeverFrozenPermanent) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingEmptyNoHookTest, Freeze) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
EXPECT_THAT(mm::FreezeSubgraph(object.header()), nullptr);
|
||||
EXPECT_TRUE(mm::IsFrozen(object.header()));
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingEmptyNoHookTest, FreezePermanent) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
object.MakePermanent();
|
||||
EXPECT_THAT(mm::FreezeSubgraph(object.header()), nullptr);
|
||||
@@ -180,6 +184,7 @@ TYPED_TEST(FreezingEmptyNoHookTest, FreezePermanent) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingEmptyNoHookTest, FreezeTwice) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
EXPECT_THAT(mm::FreezeSubgraph(object.header()), nullptr);
|
||||
EXPECT_THAT(mm::FreezeSubgraph(object.header()), nullptr);
|
||||
@@ -187,6 +192,7 @@ TYPED_TEST(FreezingEmptyNoHookTest, FreezeTwice) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingEmptyNoHookTest, FreezeForbidden) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
ASSERT_TRUE(mm::EnsureNeverFrozen(object.header()));
|
||||
EXPECT_THAT(mm::FreezeSubgraph(object.header()), object.header());
|
||||
@@ -194,6 +200,7 @@ TYPED_TEST(FreezingEmptyNoHookTest, FreezeForbidden) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingEmptyWithHookTest, Freeze) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
EXPECT_CALL(this->freezeHook(), Call(object.header()));
|
||||
EXPECT_THAT(mm::FreezeSubgraph(object.header()), nullptr);
|
||||
@@ -201,6 +208,7 @@ TYPED_TEST(FreezingEmptyWithHookTest, Freeze) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingEmptyWithHookTest, FreezePermanent) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
object.MakePermanent();
|
||||
EXPECT_CALL(this->freezeHook(), Call(_)).Times(0);
|
||||
@@ -209,6 +217,7 @@ TYPED_TEST(FreezingEmptyWithHookTest, FreezePermanent) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingEmptyWithHookTest, FreezeTwice) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
// Only called for the first freeze.
|
||||
EXPECT_CALL(this->freezeHook(), Call(object.header()));
|
||||
@@ -219,6 +228,7 @@ TYPED_TEST(FreezingEmptyWithHookTest, FreezeTwice) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingEmptyWithHookTest, FreezeForbidden) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
ASSERT_TRUE(mm::EnsureNeverFrozen(object.header()));
|
||||
EXPECT_CALL(this->freezeHook(), Call(object.header()));
|
||||
@@ -227,12 +237,14 @@ TYPED_TEST(FreezingEmptyWithHookTest, FreezeForbidden) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingNoHookTest, Freeze) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
EXPECT_THAT(mm::FreezeSubgraph(object.header()), nullptr);
|
||||
EXPECT_TRUE(mm::IsFrozen(object.header()));
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingNoHookTest, FreezePermanent) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
object.MakePermanent();
|
||||
EXPECT_THAT(mm::FreezeSubgraph(object.header()), nullptr);
|
||||
@@ -240,6 +252,7 @@ TYPED_TEST(FreezingNoHookTest, FreezePermanent) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingNoHookTest, FreezeTwice) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
EXPECT_THAT(mm::FreezeSubgraph(object.header()), nullptr);
|
||||
EXPECT_THAT(mm::FreezeSubgraph(object.header()), nullptr);
|
||||
@@ -247,6 +260,7 @@ TYPED_TEST(FreezingNoHookTest, FreezeTwice) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingNoHookTest, FreezeForbidden) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
ASSERT_TRUE(mm::EnsureNeverFrozen(object.header()));
|
||||
EXPECT_THAT(mm::FreezeSubgraph(object.header()), object.header());
|
||||
@@ -254,6 +268,7 @@ TYPED_TEST(FreezingNoHookTest, FreezeForbidden) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingNoHookTest, FreezeTree) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam field1;
|
||||
TypeParam field2;
|
||||
@@ -269,6 +284,7 @@ TYPED_TEST(FreezingNoHookTest, FreezeTree) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingNoHookTest, FreezeTreePermanent) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
object.MakePermanent();
|
||||
TypeParam field1;
|
||||
@@ -288,6 +304,7 @@ TYPED_TEST(FreezingNoHookTest, FreezeTreePermanent) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingNoHookTest, FreezeTreePermanentLeaf) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam field1;
|
||||
field1.MakePermanent();
|
||||
@@ -304,6 +321,7 @@ TYPED_TEST(FreezingNoHookTest, FreezeTreePermanentLeaf) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingNoHookTest, FreezeTreeTwice) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam field1;
|
||||
TypeParam field2;
|
||||
@@ -320,6 +338,7 @@ TYPED_TEST(FreezingNoHookTest, FreezeTreeTwice) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingNoHookTest, FreezeTreeForbidden) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam field1;
|
||||
TypeParam field2;
|
||||
@@ -336,6 +355,7 @@ TYPED_TEST(FreezingNoHookTest, FreezeTreeForbidden) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingNoHookTest, FreezeTreeForbiddenByField) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam field1;
|
||||
TypeParam field2;
|
||||
@@ -352,6 +372,7 @@ TYPED_TEST(FreezingNoHookTest, FreezeTreeForbiddenByField) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingNoHookTest, FreezeTreeRecursive) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam inner1;
|
||||
TypeParam inner2;
|
||||
@@ -365,6 +386,7 @@ TYPED_TEST(FreezingNoHookTest, FreezeTreeRecursive) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingNoHookTest, FreezeTreeRecursivePermanent) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
object.MakePermanent();
|
||||
TypeParam inner1;
|
||||
@@ -381,6 +403,7 @@ TYPED_TEST(FreezingNoHookTest, FreezeTreeRecursivePermanent) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, Freeze) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
EXPECT_CALL(this->freezeHook(), Call(object.header()));
|
||||
EXPECT_THAT(mm::FreezeSubgraph(object.header()), nullptr);
|
||||
@@ -388,6 +411,7 @@ TYPED_TEST(FreezingWithHookTest, Freeze) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, FreezePermanent) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
object.MakePermanent();
|
||||
EXPECT_CALL(this->freezeHook(), Call(_)).Times(0);
|
||||
@@ -396,6 +420,7 @@ TYPED_TEST(FreezingWithHookTest, FreezePermanent) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, FreezeTwice) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
// Only called for the first freeze.
|
||||
EXPECT_CALL(this->freezeHook(), Call(object.header()));
|
||||
@@ -406,6 +431,7 @@ TYPED_TEST(FreezingWithHookTest, FreezeTwice) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, FreezeForbidden) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
ASSERT_TRUE(mm::EnsureNeverFrozen(object.header()));
|
||||
EXPECT_CALL(this->freezeHook(), Call(object.header()));
|
||||
@@ -414,6 +440,7 @@ TYPED_TEST(FreezingWithHookTest, FreezeForbidden) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, FreezeTree) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam field1;
|
||||
TypeParam field2;
|
||||
@@ -433,6 +460,7 @@ TYPED_TEST(FreezingWithHookTest, FreezeTree) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, FreezeTreePermanent) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
object.MakePermanent();
|
||||
TypeParam field1;
|
||||
@@ -453,6 +481,7 @@ TYPED_TEST(FreezingWithHookTest, FreezeTreePermanent) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, FreezeTreePermanentLeaf) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam field1;
|
||||
field1.MakePermanent();
|
||||
@@ -473,6 +502,7 @@ TYPED_TEST(FreezingWithHookTest, FreezeTreePermanentLeaf) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, FreezeTreeTwice) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam field1;
|
||||
TypeParam field2;
|
||||
@@ -495,6 +525,7 @@ TYPED_TEST(FreezingWithHookTest, FreezeTreeTwice) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, FreezeTreeForbidden) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam field1;
|
||||
TypeParam field2;
|
||||
@@ -515,6 +546,7 @@ TYPED_TEST(FreezingWithHookTest, FreezeTreeForbidden) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, FreezeTreeForbiddenByField) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam field1;
|
||||
TypeParam field2;
|
||||
@@ -535,6 +567,7 @@ TYPED_TEST(FreezingWithHookTest, FreezeTreeForbiddenByField) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, FreezeTreeRecursive) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam inner1;
|
||||
TypeParam inner2;
|
||||
@@ -551,6 +584,7 @@ TYPED_TEST(FreezingWithHookTest, FreezeTreeRecursive) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, FreezeTreeRecursivePermanent) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
object.MakePermanent();
|
||||
TypeParam inner1;
|
||||
@@ -568,6 +602,7 @@ TYPED_TEST(FreezingWithHookTest, FreezeTreeRecursivePermanent) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, FreezeTreeWithHookRewrite) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam field1;
|
||||
TypeParam field2;
|
||||
@@ -597,6 +632,7 @@ TYPED_TEST(FreezingWithHookTest, FreezeTreeWithHookRewrite) {
|
||||
}
|
||||
|
||||
TYPED_TEST(FreezingWithHookTest, FreezeTreeForbiddenByHook) {
|
||||
ScopedMemoryInit init;
|
||||
TypeParam object;
|
||||
TypeParam field1;
|
||||
TypeParam field2;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "StableRefRegistry.hpp"
|
||||
#include "ThreadRegistry.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "ExtraObjectDataFactory.hpp"
|
||||
|
||||
namespace kotlin {
|
||||
namespace mm {
|
||||
@@ -25,6 +26,7 @@ public:
|
||||
ThreadRegistry& threadRegistry() noexcept { return threadRegistry_; }
|
||||
GlobalsRegistry& globalsRegistry() noexcept { return globalsRegistry_; }
|
||||
StableRefRegistry& stableRefRegistry() noexcept { return stableRefRegistry_; }
|
||||
ExtraObjectDataFactory& extraObjectDataFactory() noexcept { return extraObjectDataFactory_; }
|
||||
ObjectFactory<gc::GC>& objectFactory() noexcept { return objectFactory_; }
|
||||
gc::GCScheduler& gcScheduler() noexcept { return gcScheduler_; }
|
||||
gc::GC& gc() noexcept { return gc_; }
|
||||
@@ -39,6 +41,7 @@ private:
|
||||
ThreadRegistry threadRegistry_;
|
||||
GlobalsRegistry globalsRegistry_;
|
||||
StableRefRegistry stableRefRegistry_;
|
||||
ExtraObjectDataFactory extraObjectDataFactory_;
|
||||
ObjectFactory<gc::GC> objectFactory_;
|
||||
gc::GCScheduler gcScheduler_;
|
||||
gc::GC gc_;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "GC.hpp"
|
||||
#include "GCScheduler.hpp"
|
||||
#include "ObjectFactory.hpp"
|
||||
#include "ExtraObjectDataFactory.hpp"
|
||||
#include "ShadowStack.hpp"
|
||||
#include "StableRefRegistry.hpp"
|
||||
#include "ThreadLocalStorage.hpp"
|
||||
@@ -33,6 +34,7 @@ public:
|
||||
threadId_(threadId),
|
||||
globalsThreadQueue_(GlobalsRegistry::Instance()),
|
||||
stableRefThreadQueue_(StableRefRegistry::Instance()),
|
||||
extraObjectDataThreadQueue_(ExtraObjectDataFactory::Instance()),
|
||||
gcScheduler_(GlobalData::Instance().gcScheduler().NewThreadData()),
|
||||
gc_(GlobalData::Instance().gc(), *this),
|
||||
objectFactoryThreadQueue_(GlobalData::Instance().objectFactory(), gc_),
|
||||
@@ -48,6 +50,8 @@ public:
|
||||
|
||||
StableRefRegistry::ThreadQueue& stableRefThreadQueue() noexcept { return stableRefThreadQueue_; }
|
||||
|
||||
ExtraObjectDataFactory::ThreadQueue& extraObjectDataThreadQueue() noexcept { return extraObjectDataThreadQueue_; }
|
||||
|
||||
ThreadState state() noexcept { return suspensionData_.state(); }
|
||||
|
||||
ThreadState setState(ThreadState state) noexcept { return suspensionData_.setState(state); }
|
||||
@@ -69,12 +73,14 @@ public:
|
||||
globalsThreadQueue_.Publish();
|
||||
stableRefThreadQueue_.Publish();
|
||||
objectFactoryThreadQueue_.Publish();
|
||||
extraObjectDataThreadQueue_.Publish();
|
||||
}
|
||||
|
||||
void ClearForTests() noexcept {
|
||||
globalsThreadQueue_.ClearForTests();
|
||||
stableRefThreadQueue_.ClearForTests();
|
||||
objectFactoryThreadQueue_.ClearForTests();
|
||||
extraObjectDataThreadQueue_.ClearForTests();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -82,6 +88,7 @@ private:
|
||||
GlobalsRegistry::ThreadQueue globalsThreadQueue_;
|
||||
ThreadLocalStorage tls_;
|
||||
StableRefRegistry::ThreadQueue stableRefThreadQueue_;
|
||||
ExtraObjectDataFactory::ThreadQueue extraObjectDataThreadQueue_;
|
||||
ShadowStack shadowStack_;
|
||||
gc::GCSchedulerThreadData gcScheduler_;
|
||||
gc::GC::ThreadData gc_;
|
||||
|
||||
Reference in New Issue
Block a user