Put GC implementations into separate modules.

The mm module now compiles separately for each GC implementation.
This commit is contained in:
Alexander Shabalin
2021-05-04 10:23:16 +00:00
committed by Space
parent 41ab97ff1f
commit 5e456ed82b
21 changed files with 230 additions and 89 deletions
@@ -206,7 +206,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
put(ENABLE_ASSERTIONS, arguments.enableAssertions) put(ENABLE_ASSERTIONS, arguments.enableAssertions)
put(MEMORY_MODEL, when (arguments.memoryModel) { val memoryModel = when (arguments.memoryModel) {
"relaxed" -> { "relaxed" -> {
configuration.report(STRONG_WARNING, "Relaxed memory model is not yet fully functional") configuration.report(STRONG_WARNING, "Relaxed memory model is not yet fully functional")
MemoryModel.RELAXED MemoryModel.RELAXED
@@ -217,7 +217,9 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
configuration.report(ERROR, "Unsupported memory model ${arguments.memoryModel}") configuration.report(ERROR, "Unsupported memory model ${arguments.memoryModel}")
MemoryModel.STRICT MemoryModel.STRICT
} }
}) }
put(MEMORY_MODEL, memoryModel)
when { when {
arguments.generateWorkerTestRunner -> put(GENERATE_TEST_RUNNER, TestRunnerKind.WORKER) arguments.generateWorkerTestRunner -> put(GENERATE_TEST_RUNNER, TestRunnerKind.WORKER)
@@ -271,6 +273,26 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
DestroyRuntimeMode.ON_SHUTDOWN DestroyRuntimeMode.ON_SHUTDOWN
} }
}) })
val assertGcSupported = {
if (memoryModel != MemoryModel.EXPERIMENTAL) {
configuration.report(ERROR, "-Xgc is only supported for -memory-model experimental")
}
}
put(GARBAGE_COLLECTOR, when (arguments.gc) {
null -> GC.SINGLE_THREAD_MARK_SWEEP
"noop" -> {
assertGcSupported()
GC.NOOP
}
"stms" -> {
assertGcSupported()
GC.SINGLE_THREAD_MARK_SWEEP
}
else -> {
configuration.report(ERROR, "Unsupported GC ${arguments.gc}")
GC.SINGLE_THREAD_MARK_SWEEP
}
})
} }
} }
} }
@@ -305,6 +305,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value="-Xdestroy-runtime-mode", valueDescription = "<mode>", description = "When to destroy runtime. 'legacy' and 'on-shutdown' are currently supported. NOTE: 'legacy' mode is deprecated and will be removed.") @Argument(value="-Xdestroy-runtime-mode", valueDescription = "<mode>", description = "When to destroy runtime. 'legacy' and 'on-shutdown' are currently supported. NOTE: 'legacy' mode is deprecated and will be removed.")
var destroyRuntimeMode: String? = "on-shutdown" var destroyRuntimeMode: String? = "on-shutdown"
@Argument(value="-Xgc", valueDescription = "<gc>", description = "GC to use, 'noop' and 'stms' are currently supported. Works only with -memory-model experimental")
var gc: String? = null
override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> = override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> =
super.configureAnalysisFlags(collector).also { super.configureAnalysisFlags(collector).also {
val useExperimental = it[AnalysisFlags.useExperimental] as List<*> val useExperimental = it[AnalysisFlags.useExperimental] as List<*>
@@ -0,0 +1,11 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.konan
enum class GC {
NOOP,
SINGLE_THREAD_MARK_SWEEP,
}
@@ -47,6 +47,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
val memoryModel: MemoryModel get() = configuration.get(KonanConfigKeys.MEMORY_MODEL)!! val memoryModel: MemoryModel get() = configuration.get(KonanConfigKeys.MEMORY_MODEL)!!
val destroyRuntimeMode: DestroyRuntimeMode get() = configuration.get(KonanConfigKeys.DESTROY_RUNTIME_MODE)!! val destroyRuntimeMode: DestroyRuntimeMode get() = configuration.get(KonanConfigKeys.DESTROY_RUNTIME_MODE)!!
val gc: GC get() = configuration.get(KonanConfigKeys.GARBAGE_COLLECTOR)!!
val needVerifyIr: Boolean val needVerifyIr: Boolean
get() = configuration.get(KonanConfigKeys.VERIFY_IR) == true get() = configuration.get(KonanConfigKeys.VERIFY_IR) == true
@@ -161,7 +162,17 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
add("legacy_memory_manager.bc") add("legacy_memory_manager.bc")
} }
MemoryModel.EXPERIMENTAL -> { MemoryModel.EXPERIMENTAL -> {
add("experimental_memory_manager.bc") add("common_gc.bc")
when (gc) {
GC.SINGLE_THREAD_MARK_SWEEP -> {
add("experimental_memory_manager_stms.bc")
add("single_thread_ms_gc.bc")
}
GC.NOOP -> {
add("experimental_memory_manager_noop.bc")
add("noop_gc.bc")
}
}
} }
} }
if (shouldCoverLibraries || shouldCoverSources) add("profileRuntime.bc") if (shouldCoverLibraries || shouldCoverSources) add("profileRuntime.bc")
@@ -154,6 +154,7 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create("override konan.properties values") = CompilerConfigurationKey.create("override konan.properties values")
val DESTROY_RUNTIME_MODE: CompilerConfigurationKey<DestroyRuntimeMode> val DESTROY_RUNTIME_MODE: CompilerConfigurationKey<DestroyRuntimeMode>
= CompilerConfigurationKey.create("when to destroy runtime") = CompilerConfigurationKey.create("when to destroy runtime")
val GARBAGE_COLLECTOR: CompilerConfigurationKey<GC> = CompilerConfigurationKey.create("gc")
} }
} }
+70 -5
View File
@@ -41,10 +41,13 @@ bitcode {
"${target}Objc", "${target}Objc",
"${target}ExceptionsSupport", "${target}ExceptionsSupport",
"${target}LegacyMemoryManager", "${target}LegacyMemoryManager",
"${target}ExperimentalMemoryManager" "${target}ExperimentalMemoryManagerNoop",
"${target}ExperimentalMemoryManagerStms",
"${target}CommonGc",
"${target}SingleThreadMsGc",
"${target}NoopGc"
) )
includeRuntime() includeRuntime()
// TODO: Should depend on the sanitizer.
} }
create("mimalloc") { create("mimalloc") {
@@ -103,7 +106,28 @@ bitcode {
includeRuntime() includeRuntime()
} }
create("experimental_memory_manager", file("src/mm")) { create("experimental_memory_manager_noop", file("src/mm")) {
headersDirs += files("src/gc/noop/cpp", "src/gc/common/cpp")
includeRuntime()
}
create("experimental_memory_manager_stms", file("src/mm")) {
headersDirs += files("src/gc/stms/cpp", "src/gc/common/cpp")
includeRuntime()
}
create("common_gc", file("src/gc/common")) {
headersDirs += files("src/mm/cpp")
includeRuntime()
}
create("noop_gc", file("src/gc/noop")) {
headersDirs += files("src/gc/noop/cpp", "src/gc/common/cpp", "src/mm/cpp")
includeRuntime()
}
create("single_thread_ms_gc", file("src/gc/stms")) {
headersDirs += files("src/gc/stms/cpp", "src/gc/common/cpp", "src/mm/cpp")
includeRuntime() includeRuntime()
} }
} }
@@ -148,12 +172,15 @@ targetList.forEach { targetName ->
"${targetName}ExperimentalMMMimallocRuntimeTests", "${targetName}ExperimentalMMMimallocRuntimeTests",
listOf( listOf(
"${targetName}Runtime", "${targetName}Runtime",
"${targetName}ExperimentalMemoryManager", "${targetName}ExperimentalMemoryManagerStms",
"${targetName}CommonGc",
"${targetName}SingleThreadMsGc",
"${targetName}Release", "${targetName}Release",
"${targetName}Mimalloc", "${targetName}Mimalloc",
"${targetName}OptAlloc" "${targetName}OptAlloc"
) )
) { ) {
headersDirs += files("src/gc/stms/cpp", "src/gc/common/cpp", "src/mm/cpp")
includeRuntime() includeRuntime()
}) })
@@ -163,11 +190,49 @@ targetList.forEach { targetName ->
"${targetName}ExperimentalMMStdAllocRuntimeTests", "${targetName}ExperimentalMMStdAllocRuntimeTests",
listOf( listOf(
"${targetName}Runtime", "${targetName}Runtime",
"${targetName}ExperimentalMemoryManager", "${targetName}ExperimentalMemoryManagerStms",
"${targetName}CommonGc",
"${targetName}SingleThreadMsGc",
"${targetName}Release", "${targetName}Release",
"${targetName}StdAlloc" "${targetName}StdAlloc"
) )
) { ) {
headersDirs += files("src/gc/stms/cpp", "src/gc/common/cpp", "src/mm/cpp")
includeRuntime()
})
allTests.addAll(createTestTasks(
project,
targetName,
"${targetName}ExperimentalMMNoOpMimallocRuntimeTests",
listOf(
"${targetName}Runtime",
"${targetName}ExperimentalMemoryManagerNoop",
"${targetName}CommonGc",
"${targetName}NoopGc",
"${targetName}Release",
"${targetName}Mimalloc",
"${targetName}OptAlloc"
)
) {
headersDirs += files("src/gc/noop/cpp", "src/gc/common/cpp", "src/mm/cpp")
includeRuntime()
})
allTests.addAll(createTestTasks(
project,
targetName,
"${targetName}ExperimentalMMNoOpStdAllocRuntimeTests",
listOf(
"${targetName}Runtime",
"${targetName}ExperimentalMemoryManagerNoop",
"${targetName}CommonGc",
"${targetName}NoopGc",
"${targetName}Release",
"${targetName}StdAlloc"
)
) {
headersDirs += files("src/gc/noop/cpp", "src/gc/common/cpp", "src/mm/cpp")
includeRuntime() includeRuntime()
}) })
@@ -0,0 +1,6 @@
/*
* Copyright 2010-2021 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 "MarkAndSweepUtils.hpp"
@@ -3,10 +3,10 @@
* that can be found in the LICENSE file. * that can be found in the LICENSE file.
*/ */
#ifndef RUNTIME_MM_MARK_AND_SWEEP_UTILS_H #ifndef RUNTIME_GC_COMMON_MARK_AND_SWEEP_UTILS_H
#define RUNTIME_MM_MARK_AND_SWEEP_UTILS_H #define RUNTIME_GC_COMMON_MARK_AND_SWEEP_UTILS_H
#include "../ExtraObjectData.hpp" #include "ExtraObjectData.hpp"
#include "FinalizerHooks.hpp" #include "FinalizerHooks.hpp"
#include "Memory.h" #include "Memory.h"
#include "ObjectTraversal.hpp" #include "ObjectTraversal.hpp"
@@ -14,7 +14,7 @@
#include "Types.h" #include "Types.h"
namespace kotlin { namespace kotlin {
namespace mm { namespace gc {
// TODO: Because of `graySet` this implementation may allocate heap memory during GC. // TODO: Because of `graySet` this implementation may allocate heap memory during GC.
template <typename Traits> template <typename Traits>
@@ -73,7 +73,7 @@ typename Traits::ObjectFactory::FinalizerQueue Sweep(typename Traits::ObjectFact
return finalizerQueue; return finalizerQueue;
} }
} // namespace mm } // namespace gc
} // namespace kotlin } // namespace kotlin
#endif // RUNTIME_MM_MARK_AND_SWEEP_UTILS_H #endif // RUNTIME_GC_COMMON_MARK_AND_SWEEP_UTILS_H
@@ -138,7 +138,7 @@ public:
void Mark(std::initializer_list<std::reference_wrapper<BaseObject>> graySet) { void Mark(std::initializer_list<std::reference_wrapper<BaseObject>> graySet) {
KStdVector<ObjHeader*> objects; KStdVector<ObjHeader*> objects;
for (auto& object : graySet) objects.push_back(object.get().GetObjHeader()); for (auto& object : graySet) objects.push_back(object.get().GetObjHeader());
mm::Mark<ScopedMarkTraits>(std::move(objects)); gc::Mark<ScopedMarkTraits>(std::move(objects));
} }
private: private:
@@ -8,8 +8,8 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "../ObjectFactory.hpp"
#include "FinalizerHooksTestSupport.hpp" #include "FinalizerHooksTestSupport.hpp"
#include "ObjectFactory.hpp"
#include "ObjectTestSupport.hpp" #include "ObjectTestSupport.hpp"
using namespace kotlin; using namespace kotlin;
@@ -184,7 +184,7 @@ public:
} }
KStdVector<ObjHeader*> Sweep() { KStdVector<ObjHeader*> Sweep() {
auto finalizers = mm::Sweep<SweepTraits>(objectFactory_); auto finalizers = gc::Sweep<SweepTraits>(objectFactory_);
KStdVector<ObjHeader*> objects; KStdVector<ObjHeader*> objects;
for (auto node : finalizers.IterForTests()) { for (auto node : finalizers.IterForTests()) {
objects.push_back(node.IsArray() ? node.GetArrayHeader()->obj() : node.GetObjHeader()); objects.push_back(node.IsArray() ? node.GetArrayHeader()->obj() : node.GetObjHeader());
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2021 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_GC_NOOP_GC_H
#define RUNTIME_GC_NOOP_GC_H
#include "NoOpGC.hpp"
namespace kotlin {
namespace gc {
using GC = kotlin::gc::NoOpGC;
} // namespace gc
} // namespace kotlin
#endif // RUNTIME_GC_NOOP_GC_H
@@ -0,0 +1,6 @@
/*
* Copyright 2010-2021 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 "NoOpGC.hpp"
@@ -3,15 +3,15 @@
* that can be found in the LICENSE file. * that can be found in the LICENSE file.
*/ */
#ifndef RUNTIME_MM_NOOP_GC_H #ifndef RUNTIME_GC_NOOP_NOOP_GC_H
#define RUNTIME_MM_NOOP_GC_H #define RUNTIME_GC_NOOP_NOOP_GC_H
#include <cstddef> #include <cstddef>
#include "Utils.hpp" #include "Utils.hpp"
namespace kotlin { namespace kotlin {
namespace mm { namespace gc {
// No-op GC is a GC that does not free memory. // No-op GC is a GC that does not free memory.
// TODO: It can be made more efficient. // TODO: It can be made more efficient.
@@ -52,7 +52,7 @@ private:
size_t allocationThresholdBytes_ = 0; size_t allocationThresholdBytes_ = 0;
}; };
} // namespace mm } // namespace gc
} // namespace kotlin } // namespace kotlin
#endif // RUNTIME_MM_NOOP_GC_H #endif // RUNTIME_GC_NOOP_NOOP_GC_H
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2021 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_GC_STMS_GC_H
#define RUNTIME_GC_STMS_GC_H
#include "SingleThreadMarkAndSweep.hpp"
namespace kotlin {
namespace gc {
using GC = kotlin::gc::SingleThreadMarkAndSweep;
} // namespace gc
} // namespace kotlin
#endif // RUNTIME_GC_STMS_GC_H
@@ -5,13 +5,13 @@
#include "SingleThreadMarkAndSweep.hpp" #include "SingleThreadMarkAndSweep.hpp"
#include "../GlobalData.hpp" #include "GlobalData.hpp"
#include "../RootSet.hpp"
#include "../ThreadData.hpp"
#include "../ThreadRegistry.hpp"
#include "MarkAndSweepUtils.hpp" #include "MarkAndSweepUtils.hpp"
#include "Memory.h" #include "Memory.h"
#include "RootSet.hpp"
#include "Runtime.h" #include "Runtime.h"
#include "ThreadData.hpp"
#include "ThreadRegistry.hpp"
using namespace kotlin; using namespace kotlin;
@@ -19,57 +19,57 @@ namespace {
struct MarkTraits { struct MarkTraits {
static bool IsMarked(ObjHeader* object) noexcept { static bool IsMarked(ObjHeader* object) noexcept {
auto& objectData = mm::ObjectFactory<mm::SingleThreadMarkAndSweep>::NodeRef::From(object).GCObjectData(); auto& objectData = mm::ObjectFactory<gc::SingleThreadMarkAndSweep>::NodeRef::From(object).GCObjectData();
return objectData.color() == mm::SingleThreadMarkAndSweep::ObjectData::Color::kBlack; return objectData.color() == gc::SingleThreadMarkAndSweep::ObjectData::Color::kBlack;
} }
static bool TryMark(ObjHeader* object) noexcept { static bool TryMark(ObjHeader* object) noexcept {
auto& objectData = mm::ObjectFactory<mm::SingleThreadMarkAndSweep>::NodeRef::From(object).GCObjectData(); auto& objectData = mm::ObjectFactory<gc::SingleThreadMarkAndSweep>::NodeRef::From(object).GCObjectData();
if (objectData.color() == mm::SingleThreadMarkAndSweep::ObjectData::Color::kBlack) return false; if (objectData.color() == gc::SingleThreadMarkAndSweep::ObjectData::Color::kBlack) return false;
objectData.setColor(mm::SingleThreadMarkAndSweep::ObjectData::Color::kBlack); objectData.setColor(gc::SingleThreadMarkAndSweep::ObjectData::Color::kBlack);
return true; return true;
}; };
}; };
struct SweepTraits { struct SweepTraits {
using ObjectFactory = mm::ObjectFactory<mm::SingleThreadMarkAndSweep>; using ObjectFactory = mm::ObjectFactory<gc::SingleThreadMarkAndSweep>;
static bool TryResetMark(ObjectFactory::NodeRef node) noexcept { static bool TryResetMark(ObjectFactory::NodeRef node) noexcept {
auto& objectData = node.GCObjectData(); auto& objectData = node.GCObjectData();
if (objectData.color() == mm::SingleThreadMarkAndSweep::ObjectData::Color::kWhite) return false; if (objectData.color() == gc::SingleThreadMarkAndSweep::ObjectData::Color::kWhite) return false;
objectData.setColor(mm::SingleThreadMarkAndSweep::ObjectData::Color::kWhite); objectData.setColor(gc::SingleThreadMarkAndSweep::ObjectData::Color::kWhite);
return true; return true;
} }
}; };
struct FinalizeTraits { struct FinalizeTraits {
using ObjectFactory = mm::ObjectFactory<mm::SingleThreadMarkAndSweep>; using ObjectFactory = mm::ObjectFactory<gc::SingleThreadMarkAndSweep>;
}; };
} // namespace } // namespace
void mm::SingleThreadMarkAndSweep::ThreadData::SafePointFunctionEpilogue() noexcept { void gc::SingleThreadMarkAndSweep::ThreadData::SafePointFunctionEpilogue() noexcept {
if (gc_.GetThreshold() == 0 || safePointsCounter_ % gc_.GetThreshold() == 0) { if (gc_.GetThreshold() == 0 || safePointsCounter_ % gc_.GetThreshold() == 0) {
PerformFullGC(); PerformFullGC();
} }
++safePointsCounter_; ++safePointsCounter_;
} }
void mm::SingleThreadMarkAndSweep::ThreadData::SafePointLoopBody() noexcept { void gc::SingleThreadMarkAndSweep::ThreadData::SafePointLoopBody() noexcept {
if (gc_.GetThreshold() == 0 || safePointsCounter_ % gc_.GetThreshold() == 0) { if (gc_.GetThreshold() == 0 || safePointsCounter_ % gc_.GetThreshold() == 0) {
PerformFullGC(); PerformFullGC();
} }
++safePointsCounter_; ++safePointsCounter_;
} }
void mm::SingleThreadMarkAndSweep::ThreadData::SafePointExceptionUnwind() noexcept { void gc::SingleThreadMarkAndSweep::ThreadData::SafePointExceptionUnwind() noexcept {
if (gc_.GetThreshold() == 0 || safePointsCounter_ % gc_.GetThreshold() == 0) { if (gc_.GetThreshold() == 0 || safePointsCounter_ % gc_.GetThreshold() == 0) {
PerformFullGC(); PerformFullGC();
} }
++safePointsCounter_; ++safePointsCounter_;
} }
void mm::SingleThreadMarkAndSweep::ThreadData::SafePointAllocation(size_t size) noexcept { void gc::SingleThreadMarkAndSweep::ThreadData::SafePointAllocation(size_t size) noexcept {
size_t allocationOverhead = size_t allocationOverhead =
gc_.GetAllocationThresholdBytes() == 0 ? allocatedBytes_ : allocatedBytes_ % gc_.GetAllocationThresholdBytes(); gc_.GetAllocationThresholdBytes() == 0 ? allocatedBytes_ : allocatedBytes_ % gc_.GetAllocationThresholdBytes();
if (allocationOverhead + size >= gc_.GetAllocationThresholdBytes()) { if (allocationOverhead + size >= gc_.GetAllocationThresholdBytes()) {
@@ -78,15 +78,15 @@ void mm::SingleThreadMarkAndSweep::ThreadData::SafePointAllocation(size_t size)
allocatedBytes_ += size; allocatedBytes_ += size;
} }
void mm::SingleThreadMarkAndSweep::ThreadData::PerformFullGC() noexcept { void gc::SingleThreadMarkAndSweep::ThreadData::PerformFullGC() noexcept {
gc_.PerformFullGC(); gc_.PerformFullGC();
} }
void mm::SingleThreadMarkAndSweep::ThreadData::OnOOM(size_t size) noexcept { void gc::SingleThreadMarkAndSweep::ThreadData::OnOOM(size_t size) noexcept {
PerformFullGC(); PerformFullGC();
} }
void mm::SingleThreadMarkAndSweep::PerformFullGC() noexcept { void gc::SingleThreadMarkAndSweep::PerformFullGC() noexcept {
RuntimeAssert(running_ == false, "Cannot have been called during another collection"); RuntimeAssert(running_ == false, "Cannot have been called during another collection");
running_ = true; running_ = true;
@@ -106,8 +106,8 @@ void mm::SingleThreadMarkAndSweep::PerformFullGC() noexcept {
} }
} }
mm::Mark<MarkTraits>(std::move(graySet)); gc::Mark<MarkTraits>(std::move(graySet));
auto finalizerQueue = mm::Sweep<SweepTraits>(mm::GlobalData::Instance().objectFactory()); auto finalizerQueue = gc::Sweep<SweepTraits>(mm::GlobalData::Instance().objectFactory());
running_ = false; running_ = false;
@@ -3,8 +3,8 @@
* that can be found in the LICENSE file. * that can be found in the LICENSE file.
*/ */
#ifndef RUNTIME_MM_GC_SINGLE_THREAD_MARK_AND_SWEEP_H #ifndef RUNTIME_GC_STMS_SINGLE_THREAD_MARK_AND_SWEEP_H
#define RUNTIME_MM_GC_SINGLE_THREAD_MARK_AND_SWEEP_H #define RUNTIME_GC_STMS_SINGLE_THREAD_MARK_AND_SWEEP_H
#include <cstddef> #include <cstddef>
@@ -12,7 +12,7 @@
#include "Utils.hpp" #include "Utils.hpp"
namespace kotlin { namespace kotlin {
namespace mm { namespace gc {
// Stop-the-world Mark-and-Sweep for a single mutator // Stop-the-world Mark-and-Sweep for a single mutator
class SingleThreadMarkAndSweep : private Pinned { class SingleThreadMarkAndSweep : private Pinned {
@@ -72,7 +72,7 @@ private:
size_t allocationThresholdBytes_ = 10000; size_t allocationThresholdBytes_ = 10000;
}; };
} // namespace mm } // namespace gc
} // namespace kotlin } // namespace kotlin
#endif // RUNTIME_MM_GC_SINGLE_THREAD_MARK_AND_SWEEP_H #endif // RUNTIME_GC_STMS_SINGLE_THREAD_MARK_AND_SWEEP_H
@@ -8,12 +8,13 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "../ExtraObjectData.hpp" #include "ExtraObjectData.hpp"
#include "../GlobalData.hpp"
#include "../ObjectOps.hpp"
#include "../TestSupport.hpp"
#include "FinalizerHooksTestSupport.hpp" #include "FinalizerHooksTestSupport.hpp"
#include "GlobalData.hpp"
#include "ObjectOps.hpp"
#include "ObjectTestSupport.hpp" #include "ObjectTestSupport.hpp"
#include "TestSupport.hpp"
#include "ThreadData.hpp"
using namespace kotlin; using namespace kotlin;
@@ -186,10 +187,10 @@ KStdVector<ObjHeader*> Alive(mm::ThreadData& threadData) {
return objects; return objects;
} }
using Color = mm::SingleThreadMarkAndSweep::ObjectData::Color; using Color = gc::SingleThreadMarkAndSweep::ObjectData::Color;
Color GetColor(ObjHeader* objHeader) { Color GetColor(ObjHeader* objHeader) {
auto nodeRef = mm::ObjectFactory<mm::SingleThreadMarkAndSweep>::NodeRef::From(objHeader); auto nodeRef = mm::ObjectFactory<gc::SingleThreadMarkAndSweep>::NodeRef::From(objHeader);
return nodeRef.GCObjectData().color(); return nodeRef.GCObjectData().color();
} }
@@ -591,7 +592,8 @@ TEST_F(SingleThreadMarkAndSweepTest, PermanentObjects) {
GlobalPermanentObjectHolder global1{threadData}; GlobalPermanentObjectHolder global1{threadData};
GlobalObjectHolder global2{threadData}; GlobalObjectHolder global2{threadData};
test_support::Object<Payload> permanentObject{typeHolder.typeInfo()}; test_support::Object<Payload> permanentObject{typeHolder.typeInfo()};
permanentObject.header()->typeInfoOrMeta_ = setPointerBits(permanentObject.header()->typeInfoOrMeta_, OBJECT_TAG_PERMANENT_CONTAINER); permanentObject.header()->typeInfoOrMeta_ =
setPointerBits(permanentObject.header()->typeInfoOrMeta_, OBJECT_TAG_PERMANENT_CONTAINER);
RuntimeAssert(permanentObject.header()->permanent(), "Must be permanent"); RuntimeAssert(permanentObject.header()->permanent(), "Must be permanent");
global1->field1 = permanentObject.header(); global1->field1 = permanentObject.header();
-23
View File
@@ -1,23 +0,0 @@
/*
* Copyright 2010-2021 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_GC_H
#define RUNTIME_MM_GC_H
#include "gc/SingleThreadMarkAndSweep.hpp"
#include "gc/NoOpGC.hpp"
namespace kotlin {
namespace mm {
// TODO: GC should be extracted into a separate module, so that we can do different GCs without
// the need to redo the entire MM. For now changing GCs can be done by modifying `using` below.
using GC = SingleThreadMarkAndSweep;
} // namespace mm
} // namespace kotlin
#endif // RUNTIME_MM_GC_H
@@ -24,8 +24,8 @@ public:
ThreadRegistry& threadRegistry() noexcept { return threadRegistry_; } ThreadRegistry& threadRegistry() noexcept { return threadRegistry_; }
GlobalsRegistry& globalsRegistry() noexcept { return globalsRegistry_; } GlobalsRegistry& globalsRegistry() noexcept { return globalsRegistry_; }
StableRefRegistry& stableRefRegistry() noexcept { return stableRefRegistry_; } StableRefRegistry& stableRefRegistry() noexcept { return stableRefRegistry_; }
ObjectFactory<GC>& objectFactory() noexcept { return objectFactory_; } ObjectFactory<gc::GC>& objectFactory() noexcept { return objectFactory_; }
GC& gc() noexcept { return gc_; } gc::GC& gc() noexcept { return gc_; }
private: private:
GlobalData(); GlobalData();
@@ -37,8 +37,8 @@ private:
ThreadRegistry threadRegistry_; ThreadRegistry threadRegistry_;
GlobalsRegistry globalsRegistry_; GlobalsRegistry globalsRegistry_;
StableRefRegistry stableRefRegistry_; StableRefRegistry stableRefRegistry_;
ObjectFactory<GC> objectFactory_; ObjectFactory<gc::GC> objectFactory_;
GC gc_; gc::GC gc_;
}; };
} // namespace mm } // namespace mm
@@ -13,7 +13,6 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "FinalizerHooksTestSupport.hpp" #include "FinalizerHooksTestSupport.hpp"
#include "GC.hpp"
#include "ObjectTestSupport.hpp" #include "ObjectTestSupport.hpp"
#include "TestSupport.hpp" #include "TestSupport.hpp"
#include "Types.h" #include "Types.h"
@@ -51,13 +51,13 @@ public:
ThreadState setState(ThreadState state) noexcept { return state_.exchange(state); } ThreadState setState(ThreadState state) noexcept { return state_.exchange(state); }
ObjectFactory<GC>::ThreadQueue& objectFactoryThreadQueue() noexcept { return objectFactoryThreadQueue_; } ObjectFactory<gc::GC>::ThreadQueue& objectFactoryThreadQueue() noexcept { return objectFactoryThreadQueue_; }
ShadowStack& shadowStack() noexcept { return shadowStack_; } ShadowStack& shadowStack() noexcept { return shadowStack_; }
KStdVector<std::pair<ObjHeader**, ObjHeader*>>& initializingSingletons() noexcept { return initializingSingletons_; } KStdVector<std::pair<ObjHeader**, ObjHeader*>>& initializingSingletons() noexcept { return initializingSingletons_; }
GC::ThreadData& gc() noexcept { return gc_; } gc::GC::ThreadData& gc() noexcept { return gc_; }
void Publish() noexcept { void Publish() noexcept {
// TODO: These use separate locks, which is inefficient. // TODO: These use separate locks, which is inefficient.
@@ -79,8 +79,8 @@ private:
StableRefRegistry::ThreadQueue stableRefThreadQueue_; StableRefRegistry::ThreadQueue stableRefThreadQueue_;
std::atomic<ThreadState> state_; std::atomic<ThreadState> state_;
ShadowStack shadowStack_; ShadowStack shadowStack_;
GC::ThreadData gc_; gc::GC::ThreadData gc_;
ObjectFactory<GC>::ThreadQueue objectFactoryThreadQueue_; ObjectFactory<gc::GC>::ThreadQueue objectFactoryThreadQueue_;
KStdVector<std::pair<ObjHeader**, ObjHeader*>> initializingSingletons_; KStdVector<std::pair<ObjHeader**, ObjHeader*>> initializingSingletons_;
}; };