Tracking globals (#4542)
This commit is contained in:
committed by
Stanislav Erokhin
parent
66de5dceb9
commit
2057e5c8f1
+2
-2
@@ -1092,9 +1092,9 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
|||||||
val ctor = codegen.llvmFunction(defaultConstructor)
|
val ctor = codegen.llvmFunction(defaultConstructor)
|
||||||
val initFunction =
|
val initFunction =
|
||||||
if (storageKind == ObjectStorageKind.SHARED && context.config.threadsAreAllowed) {
|
if (storageKind == ObjectStorageKind.SHARED && context.config.threadsAreAllowed) {
|
||||||
context.llvm.initSharedInstanceFunction
|
context.llvm.initSingletonFunction
|
||||||
} else {
|
} else {
|
||||||
context.llvm.initInstanceFunction
|
context.llvm.initThreadLocalSingleton
|
||||||
}
|
}
|
||||||
val args = listOf(objectPtr, typeInfo, ctor)
|
val args = listOf(objectPtr, typeInfo, ctor)
|
||||||
val newValue = call(initFunction, args, Lifetime.GLOBAL, exceptionHandler)
|
val newValue = call(initFunction, args, Lifetime.GLOBAL, exceptionHandler)
|
||||||
|
|||||||
+3
-2
@@ -499,8 +499,9 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
|||||||
|
|
||||||
val allocInstanceFunction = importRtFunction("AllocInstance")
|
val allocInstanceFunction = importRtFunction("AllocInstance")
|
||||||
val allocArrayFunction = importRtFunction("AllocArrayInstance")
|
val allocArrayFunction = importRtFunction("AllocArrayInstance")
|
||||||
val initInstanceFunction = importRtFunction("InitInstance")
|
val initThreadLocalSingleton = importRtFunction("InitThreadLocalSingleton")
|
||||||
val initSharedInstanceFunction = importRtFunction("InitSharedInstance")
|
val initSingletonFunction = importRtFunction("InitSingleton")
|
||||||
|
val initAndRegisterGlobalFunction = importRtFunction("InitAndRegisterGlobal")
|
||||||
val updateHeapRefFunction = importRtFunction("UpdateHeapRef")
|
val updateHeapRefFunction = importRtFunction("UpdateHeapRef")
|
||||||
val updateStackRefFunction = importRtFunction("UpdateStackRef")
|
val updateStackRefFunction = importRtFunction("UpdateStackRef")
|
||||||
val updateReturnRefFunction = importRtFunction("UpdateReturnRef")
|
val updateReturnRefFunction = importRtFunction("UpdateReturnRef")
|
||||||
|
|||||||
+19
-6
@@ -412,15 +412,28 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
appendingTo(bbInit) {
|
appendingTo(bbInit) {
|
||||||
context.llvm.fileInitializers
|
context.llvm.fileInitializers
|
||||||
.forEach { irField ->
|
.forEach { irField ->
|
||||||
if (irField.initializer?.expression !is IrConst<*>?) {
|
if (irField.storageKind != FieldStorageKind.THREAD_LOCAL) {
|
||||||
if (irField.storageKind != FieldStorageKind.THREAD_LOCAL) {
|
val address = context.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(
|
||||||
|
functionGenerationContext
|
||||||
|
)
|
||||||
|
val initialValue = if (irField.initializer?.expression !is IrConst<*>?) {
|
||||||
val initialization = evaluateExpression(irField.initializer!!.expression)
|
val initialization = evaluateExpression(irField.initializer!!.expression)
|
||||||
val address = context.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(
|
|
||||||
functionGenerationContext
|
|
||||||
)
|
|
||||||
if (irField.storageKind == FieldStorageKind.SHARED_FROZEN)
|
if (irField.storageKind == FieldStorageKind.SHARED_FROZEN)
|
||||||
freeze(initialization, currentCodeContext.exceptionHandler)
|
freeze(initialization, currentCodeContext.exceptionHandler)
|
||||||
storeAny(initialization, address, false)
|
initialization
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
val needRegistration =
|
||||||
|
context.memoryModel == MemoryModel.EXPERIMENTAL && // only for the new MM
|
||||||
|
irField.type.binaryTypeIsReference() && // only for references
|
||||||
|
(initialValue != null || // which are initialized from heap object
|
||||||
|
!irField.isFinal) // or are not final
|
||||||
|
if (needRegistration) {
|
||||||
|
call(context.llvm.initAndRegisterGlobalFunction, listOf(address, initialValue
|
||||||
|
?: kNullObjHeaderPtr))
|
||||||
|
} else if (initialValue != null) {
|
||||||
|
storeAny(initialValue, address, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2320,7 +2320,7 @@ OBJ_GETTER(allocArrayInstance, const TypeInfo* type_info, int32_t elements) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <bool Strict>
|
template <bool Strict>
|
||||||
OBJ_GETTER(initInstance,
|
OBJ_GETTER(initThreadLocalSingleton,
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||||
ObjHeader* value = *location;
|
ObjHeader* value = *location;
|
||||||
if (value != nullptr) {
|
if (value != nullptr) {
|
||||||
@@ -2345,8 +2345,7 @@ OBJ_GETTER(initInstance,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <bool Strict>
|
template <bool Strict>
|
||||||
OBJ_GETTER(initSharedInstance,
|
OBJ_GETTER(initSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
|
||||||
#if KONAN_NO_THREADS
|
#if KONAN_NO_THREADS
|
||||||
ObjHeader* value = *location;
|
ObjHeader* value = *location;
|
||||||
if (value != nullptr) {
|
if (value != nullptr) {
|
||||||
@@ -3328,22 +3327,22 @@ OBJ_GETTER(AllocArrayInstanceRelaxed, const TypeInfo* typeInfo, int32_t elements
|
|||||||
RETURN_RESULT_OF(allocArrayInstance<false>, typeInfo, elements);
|
RETURN_RESULT_OF(allocArrayInstance<false>, typeInfo, elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
OBJ_GETTER(InitInstanceStrict,
|
OBJ_GETTER(InitThreadLocalSingletonStrict, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
RETURN_RESULT_OF(initThreadLocalSingleton<true>, location, typeInfo, ctor);
|
||||||
RETURN_RESULT_OF(initInstance<true>, location, typeInfo, ctor);
|
|
||||||
}
|
}
|
||||||
OBJ_GETTER(InitInstanceRelaxed,
|
OBJ_GETTER(InitThreadLocalSingletonRelaxed, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
RETURN_RESULT_OF(initThreadLocalSingleton<false>, location, typeInfo, ctor);
|
||||||
RETURN_RESULT_OF(initInstance<false>, location, typeInfo, ctor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OBJ_GETTER(InitSharedInstanceStrict,
|
OBJ_GETTER(InitSingletonStrict, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
RETURN_RESULT_OF(initSingleton<true>, location, typeInfo, ctor);
|
||||||
RETURN_RESULT_OF(initSharedInstance<true>, location, typeInfo, ctor);
|
|
||||||
}
|
}
|
||||||
OBJ_GETTER(InitSharedInstanceRelaxed,
|
OBJ_GETTER(InitSingletonRelaxed, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
RETURN_RESULT_OF(initSingleton<false>, location, typeInfo, ctor);
|
||||||
RETURN_RESULT_OF(initSharedInstance<false>, location, typeInfo, ctor);
|
}
|
||||||
|
|
||||||
|
void RUNTIME_NOTHROW InitAndRegisterGlobal(ObjHeader** location, const ObjHeader* initialValue) {
|
||||||
|
RuntimeCheck(false, "Global registration is impossible in legacy MM");
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_NOTHROW void SetStackRefStrict(ObjHeader** location, const ObjHeader* object) {
|
RUNTIME_NOTHROW void SetStackRefStrict(ObjHeader** location, const ObjHeader* object) {
|
||||||
|
|||||||
@@ -309,15 +309,11 @@ OBJ_GETTER(AllocInstanceRelaxed, const TypeInfo* type_info) RUNTIME_NOTHROW;
|
|||||||
OBJ_GETTER(AllocArrayInstanceStrict, const TypeInfo* type_info, int32_t elements);
|
OBJ_GETTER(AllocArrayInstanceStrict, const TypeInfo* type_info, int32_t elements);
|
||||||
OBJ_GETTER(AllocArrayInstanceRelaxed, const TypeInfo* type_info, int32_t elements);
|
OBJ_GETTER(AllocArrayInstanceRelaxed, const TypeInfo* type_info, int32_t elements);
|
||||||
|
|
||||||
OBJ_GETTER(InitInstanceStrict,
|
OBJ_GETTER(InitThreadLocalSingletonStrict, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
OBJ_GETTER(InitThreadLocalSingletonRelaxed, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
||||||
OBJ_GETTER(InitInstanceRelaxed,
|
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
|
||||||
|
|
||||||
OBJ_GETTER(InitSharedInstanceStrict,
|
OBJ_GETTER(InitSingletonStrict, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
OBJ_GETTER(InitSingletonRelaxed, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
||||||
OBJ_GETTER(InitSharedInstanceRelaxed,
|
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
|
||||||
|
|
||||||
MODEL_VARIANTS(void, SetStackRef, ObjHeader** location, const ObjHeader* object);
|
MODEL_VARIANTS(void, SetStackRef, ObjHeader** location, const ObjHeader* object);
|
||||||
MODEL_VARIANTS(void, SetHeapRef, ObjHeader** location, const ObjHeader* object);
|
MODEL_VARIANTS(void, SetHeapRef, ObjHeader** location, const ObjHeader* object);
|
||||||
|
|||||||
@@ -25,8 +25,9 @@ void ensureUsed(Ret (*f)(Args...)) {
|
|||||||
void EnsureDeclarationsEmitted() {
|
void EnsureDeclarationsEmitted() {
|
||||||
ensureUsed(AllocInstance);
|
ensureUsed(AllocInstance);
|
||||||
ensureUsed(AllocArrayInstance);
|
ensureUsed(AllocArrayInstance);
|
||||||
ensureUsed(InitInstance);
|
ensureUsed(InitThreadLocalSingleton);
|
||||||
ensureUsed(InitSharedInstance);
|
ensureUsed(InitSingleton);
|
||||||
|
ensureUsed(InitAndRegisterGlobal);
|
||||||
ensureUsed(UpdateHeapRef);
|
ensureUsed(UpdateHeapRef);
|
||||||
ensureUsed(UpdateStackRef);
|
ensureUsed(UpdateStackRef);
|
||||||
ensureUsed(UpdateReturnRef);
|
ensureUsed(UpdateReturnRef);
|
||||||
|
|||||||
@@ -142,11 +142,14 @@ OBJ_GETTER(AllocInstance, const TypeInfo* type_info) RUNTIME_NOTHROW;
|
|||||||
|
|
||||||
OBJ_GETTER(AllocArrayInstance, const TypeInfo* type_info, int32_t elements);
|
OBJ_GETTER(AllocArrayInstance, const TypeInfo* type_info, int32_t elements);
|
||||||
|
|
||||||
OBJ_GETTER(InitInstance,
|
OBJ_GETTER(InitThreadLocalSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
|
||||||
|
|
||||||
OBJ_GETTER(InitSharedInstance,
|
OBJ_GETTER(InitSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
|
||||||
|
// `initialValue` may be `nullptr`, which signifies that the appropriate initial value was already
|
||||||
|
// set by static initialization.
|
||||||
|
// TODO: When global initialization becomes lazy, this signature won't do.
|
||||||
|
void InitAndRegisterGlobal(ObjHeader** location, const ObjHeader* initialValue) RUNTIME_NOTHROW;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Object reference management.
|
// Object reference management.
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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_MULTI_SOURCE_QUEUE_H
|
||||||
|
#define RUNTIME_MULTI_SOURCE_QUEUE_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
namespace kotlin {
|
||||||
|
|
||||||
|
// A queue that is constructed by collecting subqueues from several `Producer`s.
|
||||||
|
template <typename T>
|
||||||
|
class MultiSourceQueue {
|
||||||
|
public:
|
||||||
|
class Producer {
|
||||||
|
public:
|
||||||
|
void Insert(const T& value) noexcept { queue_.push_back(value); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class MultiSourceQueue;
|
||||||
|
|
||||||
|
std::list<T> queue_;
|
||||||
|
};
|
||||||
|
|
||||||
|
using Iterator = typename std::list<T>::iterator;
|
||||||
|
|
||||||
|
Iterator begin() noexcept { return commonQueue_.begin(); }
|
||||||
|
Iterator end() noexcept { return commonQueue_.end(); }
|
||||||
|
|
||||||
|
// Merge `producer`s queue with `this`. `producer` will have empty queue after the call.
|
||||||
|
// This call is performed without heap allocations. TODO: Test that no allocations are happening.
|
||||||
|
void Collect(Producer* producer) noexcept { commonQueue_.splice(commonQueue_.end(), producer->queue_); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Using `std::list` as it allows to implement `Collect` without memory allocations,
|
||||||
|
// which is important for GC mark phase.
|
||||||
|
std::list<T> commonQueue_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace kotlin
|
||||||
|
|
||||||
|
#endif // RUNTIME_MULTI_SOURCE_QUEUE_H
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* 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 "MultiSourceQueue.hpp"
|
||||||
|
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
using namespace kotlin;
|
||||||
|
|
||||||
|
using IntQueue = MultiSourceQueue<int>;
|
||||||
|
|
||||||
|
TEST(MultiSourceQueueTest, Empty) {
|
||||||
|
IntQueue queue;
|
||||||
|
|
||||||
|
std::vector<int> actual;
|
||||||
|
for (int element : queue) {
|
||||||
|
actual.push_back(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_THAT(actual, testing::IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MultiSourceQueueTest, DoNotCollect) {
|
||||||
|
IntQueue queue;
|
||||||
|
IntQueue::Producer producer;
|
||||||
|
|
||||||
|
producer.Insert(1);
|
||||||
|
producer.Insert(2);
|
||||||
|
|
||||||
|
std::vector<int> actual;
|
||||||
|
for (int element : queue) {
|
||||||
|
actual.push_back(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_THAT(actual, testing::IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MultiSourceQueueTest, Collect) {
|
||||||
|
IntQueue queue;
|
||||||
|
IntQueue::Producer producer1;
|
||||||
|
IntQueue::Producer producer2;
|
||||||
|
|
||||||
|
producer1.Insert(1);
|
||||||
|
producer1.Insert(2);
|
||||||
|
producer2.Insert(10);
|
||||||
|
producer2.Insert(20);
|
||||||
|
|
||||||
|
queue.Collect(&producer1);
|
||||||
|
queue.Collect(&producer2);
|
||||||
|
|
||||||
|
std::vector<int> actual;
|
||||||
|
for (int element : queue) {
|
||||||
|
actual.push_back(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_THAT(actual, testing::ElementsAre(1, 2, 10, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MultiSourceQueueTest, CollectSeveralTimes) {
|
||||||
|
IntQueue queue;
|
||||||
|
IntQueue::Producer producer;
|
||||||
|
|
||||||
|
// Add 2 elements and collect.
|
||||||
|
producer.Insert(1);
|
||||||
|
producer.Insert(2);
|
||||||
|
queue.Collect(&producer);
|
||||||
|
|
||||||
|
// Add another element and collect.
|
||||||
|
producer.Insert(3);
|
||||||
|
queue.Collect(&producer);
|
||||||
|
|
||||||
|
// Collect without adding elements.
|
||||||
|
queue.Collect(&producer);
|
||||||
|
|
||||||
|
// Add yet another two elements and collect.
|
||||||
|
producer.Insert(4);
|
||||||
|
producer.Insert(5);
|
||||||
|
queue.Collect(&producer);
|
||||||
|
|
||||||
|
std::vector<int> actual;
|
||||||
|
for (int element : queue) {
|
||||||
|
actual.push_back(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_THAT(actual, testing::ElementsAre(1, 2, 3, 4, 5));
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#ifndef RUNTIME_MM_GLOBAL_DATA_H
|
#ifndef RUNTIME_MM_GLOBAL_DATA_H
|
||||||
#define RUNTIME_MM_GLOBAL_DATA_H
|
#define RUNTIME_MM_GLOBAL_DATA_H
|
||||||
|
|
||||||
|
#include "GlobalsRegistry.hpp"
|
||||||
#include "ThreadRegistry.hpp"
|
#include "ThreadRegistry.hpp"
|
||||||
#include "Utils.hpp"
|
#include "Utils.hpp"
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ public:
|
|||||||
static GlobalData& Instance() noexcept { return instance_; }
|
static GlobalData& Instance() noexcept { return instance_; }
|
||||||
|
|
||||||
ThreadRegistry& threadRegistry() { return threadRegistry_; }
|
ThreadRegistry& threadRegistry() { return threadRegistry_; }
|
||||||
|
GlobalsRegistry& globalsRegistry() { return globalsRegistry_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GlobalData();
|
GlobalData();
|
||||||
@@ -26,6 +28,7 @@ private:
|
|||||||
static GlobalData instance_;
|
static GlobalData instance_;
|
||||||
|
|
||||||
ThreadRegistry threadRegistry_;
|
ThreadRegistry threadRegistry_;
|
||||||
|
GlobalsRegistry globalsRegistry_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mm
|
} // namespace mm
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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 "GlobalsRegistry.hpp"
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
#include "GlobalData.hpp"
|
||||||
|
#include "ThreadData.hpp"
|
||||||
|
|
||||||
|
using namespace kotlin;
|
||||||
|
|
||||||
|
// static
|
||||||
|
mm::GlobalsRegistry& mm::GlobalsRegistry::Instance() noexcept {
|
||||||
|
return GlobalData::Instance().globalsRegistry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mm::GlobalsRegistry::RegisterStorageForGlobal(mm::ThreadData* threadData, ObjHeader** location) noexcept {
|
||||||
|
threadData->globalsThreadQueue()->Insert(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mm::GlobalsRegistry::ProcessThread(mm::ThreadData* threadData) noexcept {
|
||||||
|
RuntimeAssert(threadData->isWaitingForGC(), "Thread must be waiting for GC to complete.");
|
||||||
|
globals_.Collect(threadData->globalsThreadQueue());
|
||||||
|
}
|
||||||
|
|
||||||
|
mm::GlobalsRegistry::GlobalsRegistry() = default;
|
||||||
|
mm::GlobalsRegistry::~GlobalsRegistry() = default;
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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_GLOBALS_REGISTRY_H
|
||||||
|
#define RUNTIME_MM_GLOBALS_REGISTRY_H
|
||||||
|
|
||||||
|
#include "Memory.h"
|
||||||
|
#include "MultiSourceQueue.hpp"
|
||||||
|
#include "ThreadRegistry.hpp"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
namespace kotlin {
|
||||||
|
namespace mm {
|
||||||
|
|
||||||
|
class GlobalsRegistry : Pinned {
|
||||||
|
public:
|
||||||
|
using ThreadQueue = MultiSourceQueue<ObjHeader**>::Producer;
|
||||||
|
|
||||||
|
using Iterator = std::list<ObjHeader**>::iterator;
|
||||||
|
|
||||||
|
static GlobalsRegistry& Instance() noexcept;
|
||||||
|
|
||||||
|
void RegisterStorageForGlobal(mm::ThreadData* threadData, ObjHeader** location) noexcept;
|
||||||
|
|
||||||
|
// Collect globals from thread corresponding to `threadData`. Thread must be waiting for GC.
|
||||||
|
// Only one thread can call this method.
|
||||||
|
void ProcessThread(mm::ThreadData* threadData) noexcept;
|
||||||
|
|
||||||
|
// These must be called on the same thread as `ProcessThread` to avoid races.
|
||||||
|
// TODO: Iteration over `globals_` will be slow, because it's `std::list` collected at different times from
|
||||||
|
// different threads, and so the nodes are all over the memory. Use metrics to understand how
|
||||||
|
// much of a problem is it.
|
||||||
|
Iterator begin() noexcept { return globals_.begin(); }
|
||||||
|
Iterator end() noexcept { return globals_.end(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class GlobalData;
|
||||||
|
|
||||||
|
GlobalsRegistry();
|
||||||
|
~GlobalsRegistry();
|
||||||
|
|
||||||
|
MultiSourceQueue<ObjHeader**> globals_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mm
|
||||||
|
} // namespace kotlin
|
||||||
|
|
||||||
|
#endif // RUNTIME_MM_GLOBALS_REGISTRY_H
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
|
|
||||||
|
#include "GlobalsRegistry.hpp"
|
||||||
#include "ThreadData.hpp"
|
#include "ThreadData.hpp"
|
||||||
#include "ThreadRegistry.hpp"
|
#include "ThreadRegistry.hpp"
|
||||||
#include "Utils.hpp"
|
#include "Utils.hpp"
|
||||||
@@ -39,3 +40,18 @@ extern "C" MemoryState* InitMemory(bool firstRuntime) {
|
|||||||
extern "C" void DeinitMemory(MemoryState* state, bool destroyRuntime) {
|
extern "C" void DeinitMemory(MemoryState* state, bool destroyRuntime) {
|
||||||
mm::ThreadRegistry::Instance().Unregister(FromMemoryState(state));
|
mm::ThreadRegistry::Instance().Unregister(FromMemoryState(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" OBJ_GETTER(InitSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||||
|
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
|
||||||
|
// TODO: This should only be called if singleton is actually created here. It's possible that the
|
||||||
|
// singleton will be created on a different thread and here we should check that, instead of creating
|
||||||
|
// another one (and registering `location` twice).
|
||||||
|
mm::GlobalsRegistry::Instance().RegisterStorageForGlobal(threadData, location);
|
||||||
|
RuntimeCheck(false, "Unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" RUNTIME_NOTHROW void InitAndRegisterGlobal(ObjHeader** location, const ObjHeader* initialValue) {
|
||||||
|
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
|
||||||
|
mm::GlobalsRegistry::Instance().RegisterStorageForGlobal(threadData, location);
|
||||||
|
RuntimeCheck(false, "Unimplemented");
|
||||||
|
}
|
||||||
|
|||||||
@@ -59,11 +59,7 @@ OBJ_GETTER(AllocArrayInstance, const TypeInfo* type_info, int32_t elements) {
|
|||||||
RuntimeCheck(false, "Unimplemented");
|
RuntimeCheck(false, "Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
OBJ_GETTER(InitInstance, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
OBJ_GETTER(InitThreadLocalSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||||
RuntimeCheck(false, "Unimplemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
OBJ_GETTER(InitSharedInstance, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
|
||||||
RuntimeCheck(false, "Unimplemented");
|
RuntimeCheck(false, "Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "GlobalsRegistry.hpp"
|
||||||
#include "Utils.hpp"
|
#include "Utils.hpp"
|
||||||
|
|
||||||
namespace kotlin {
|
namespace kotlin {
|
||||||
@@ -23,8 +24,16 @@ public:
|
|||||||
|
|
||||||
pthread_t threadId() const noexcept { return threadId_; }
|
pthread_t threadId() const noexcept { return threadId_; }
|
||||||
|
|
||||||
|
bool isWaitingForGC() const noexcept {
|
||||||
|
// TODO: Implement.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalsRegistry::ThreadQueue* globalsThreadQueue() noexcept { return &globalsThreadQueue_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const pthread_t threadId_;
|
const pthread_t threadId_;
|
||||||
|
GlobalsRegistry::ThreadQueue globalsThreadQueue_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mm
|
} // namespace mm
|
||||||
|
|||||||
@@ -19,14 +19,12 @@ OBJ_GETTER(AllocArrayInstance, const TypeInfo* typeInfo, int32_t elements) {
|
|||||||
RETURN_RESULT_OF(AllocArrayInstanceRelaxed, typeInfo, elements);
|
RETURN_RESULT_OF(AllocArrayInstanceRelaxed, typeInfo, elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
OBJ_GETTER(InitInstance,
|
OBJ_GETTER(InitThreadLocalSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
RETURN_RESULT_OF(InitThreadLocalSingletonRelaxed, location, typeInfo, ctor);
|
||||||
RETURN_RESULT_OF(InitInstanceRelaxed, location, typeInfo, ctor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OBJ_GETTER(InitSharedInstance,
|
OBJ_GETTER(InitSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
RETURN_RESULT_OF(InitSingletonRelaxed, location, typeInfo, ctor);
|
||||||
RETURN_RESULT_OF(InitSharedInstanceRelaxed, location, typeInfo, ctor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_NOTHROW void ReleaseHeapRef(const ObjHeader* object) {
|
RUNTIME_NOTHROW void ReleaseHeapRef(const ObjHeader* object) {
|
||||||
|
|||||||
@@ -19,14 +19,12 @@ OBJ_GETTER(AllocArrayInstance, const TypeInfo* typeInfo, int32_t elements) {
|
|||||||
RETURN_RESULT_OF(AllocArrayInstanceStrict, typeInfo, elements);
|
RETURN_RESULT_OF(AllocArrayInstanceStrict, typeInfo, elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
OBJ_GETTER(InitInstance,
|
OBJ_GETTER(InitThreadLocalSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
RETURN_RESULT_OF(InitThreadLocalSingletonStrict, location, typeInfo, ctor);
|
||||||
RETURN_RESULT_OF(InitInstanceStrict, location, typeInfo, ctor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OBJ_GETTER(InitSharedInstance,
|
OBJ_GETTER(InitSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
RETURN_RESULT_OF(InitSingletonStrict, location, typeInfo, ctor);
|
||||||
RETURN_RESULT_OF(InitSharedInstanceStrict, location, typeInfo, ctor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_NOTHROW void ReleaseHeapRef(const ObjHeader* object) {
|
RUNTIME_NOTHROW void ReleaseHeapRef(const ObjHeader* object) {
|
||||||
|
|||||||
Reference in New Issue
Block a user