Make NoOp GC support multiple mutators
This commit is contained in:
committed by
Space
parent
792ac6ab63
commit
73533e4b19
@@ -1092,8 +1092,11 @@ standaloneTest("leakMemoryWithWorkerTermination") {
|
|||||||
disabled = (project.testTarget == 'wasm32') || // Needs pthreads.
|
disabled = (project.testTarget == 'wasm32') || // Needs pthreads.
|
||||||
isExperimentalMM // Experimental MM doesn't support multiple mutators yet.
|
isExperimentalMM // Experimental MM doesn't support multiple mutators yet.
|
||||||
source = "runtime/workers/leak_memory_with_worker_termination.kt"
|
source = "runtime/workers/leak_memory_with_worker_termination.kt"
|
||||||
expectedExitStatusChecker = { it != 0 }
|
|
||||||
outputChecker = { s -> s.contains("Memory leaks detected, 1 objects leaked!") }
|
if (!isExperimentalMM) { // Experimental MM will not report memory leaks.
|
||||||
|
expectedExitStatusChecker = { it != 0 }
|
||||||
|
outputChecker = { s -> s.contains("Memory leaks detected, 1 objects leaked!") }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task superFunCall(type: KonanLocalTest) {
|
task superFunCall(type: KonanLocalTest) {
|
||||||
@@ -4494,9 +4497,15 @@ standaloneTest("interop_objc_illegal_sharing") {
|
|||||||
isExperimentalMM // Experimental MM doesn't support multiple mutators and thread state switching for ObjC interop yet.
|
isExperimentalMM // Experimental MM doesn't support multiple mutators and thread state switching for ObjC interop yet.
|
||||||
source = "interop/objc/illegal_sharing.kt"
|
source = "interop/objc/illegal_sharing.kt"
|
||||||
UtilsKt.dependsOnPlatformLibs(it)
|
UtilsKt.dependsOnPlatformLibs(it)
|
||||||
expectedExitStatusChecker = { it != 0 }
|
if (isExperimentalMM) {
|
||||||
outputChecker = {
|
outputChecker = {
|
||||||
it.startsWith("Before") && !it.contains("After")
|
it.startsWith("Before") && it.contains("After")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expectedExitStatusChecker = { it != 0 }
|
||||||
|
outputChecker = {
|
||||||
|
it.startsWith("Before") && !it.contains("After")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4614,6 +4623,9 @@ dynamicTest("interop_migrating_main_thread") {
|
|||||||
isExperimentalMM // Experimental MM doesn't support multiple mutators yet.
|
isExperimentalMM // Experimental MM doesn't support multiple mutators yet.
|
||||||
source = "interop/migrating_main_thread/lib.kt"
|
source = "interop/migrating_main_thread/lib.kt"
|
||||||
flags = ['-Xdestroy-runtime-mode=on-shutdown']
|
flags = ['-Xdestroy-runtime-mode=on-shutdown']
|
||||||
|
if (isExperimentalMM) {
|
||||||
|
clangFlags = ['-DEXPERIMENTAL_MM']
|
||||||
|
}
|
||||||
cSource = "$projectDir/interop/migrating_main_thread/main.cpp"
|
cSource = "$projectDir/interop/migrating_main_thread/main.cpp"
|
||||||
clangTool = "clang++"
|
clangTool = "clang++"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ int main() {
|
|||||||
#if defined(IS_LEGACY)
|
#if defined(IS_LEGACY)
|
||||||
// Globals were reinitialized.
|
// Globals were reinitialized.
|
||||||
assert(testlib_symbols()->kotlin.root.tryReadFromA(kErrorValue) == kInitialValue);
|
assert(testlib_symbols()->kotlin.root.tryReadFromA(kErrorValue) == kInitialValue);
|
||||||
|
#elif defined(EXPERIMENTAL_MM)
|
||||||
|
// Globals are preserved.
|
||||||
|
assert(testlib_symbols()->kotlin.root.tryReadFromA(kErrorValue) == kNewValue);
|
||||||
#else
|
#else
|
||||||
// Globals are not accessible.
|
// Globals are not accessible.
|
||||||
assert(testlib_symbols()->kotlin.root.tryReadFromA(kErrorValue) == kErrorValue);
|
assert(testlib_symbols()->kotlin.root.tryReadFromA(kErrorValue) == kErrorValue);
|
||||||
|
|||||||
@@ -10,17 +10,24 @@ import kotlin.test.*
|
|||||||
import kotlin.native.concurrent.*
|
import kotlin.native.concurrent.*
|
||||||
import kotlinx.cinterop.*
|
import kotlinx.cinterop.*
|
||||||
|
|
||||||
|
class Holder(val value: Int)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun runTest1() {
|
fun runTest1() {
|
||||||
val worker = Worker.start()
|
val worker = Worker.start()
|
||||||
|
|
||||||
val future = worker.execute(TransferMode.SAFE, { }) {
|
val future = worker.execute(TransferMode.SAFE, { }) {
|
||||||
StableRef.create(Any())
|
StableRef.create(Holder(42))
|
||||||
}
|
}
|
||||||
val ref = future.result
|
val ref = future.result
|
||||||
assertFailsWith<IncorrectDereferenceException> {
|
if (kotlin.native.Platform.memoryModel == kotlin.native.MemoryModel.EXPERIMENTAL) {
|
||||||
val value = ref.get()
|
val value = ref.get()
|
||||||
println(value.toString())
|
assertEquals(value.value, 42)
|
||||||
|
} else {
|
||||||
|
assertFailsWith<IncorrectDereferenceException> {
|
||||||
|
val value = ref.get()
|
||||||
|
println(value.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
worker.requestTermination().result
|
worker.requestTermination().result
|
||||||
@@ -30,15 +37,20 @@ fun runTest1() {
|
|||||||
fun runTest2() {
|
fun runTest2() {
|
||||||
val worker = Worker.start()
|
val worker = Worker.start()
|
||||||
|
|
||||||
val mainThreadRef = StableRef.create(Any())
|
val mainThreadRef = StableRef.create(Holder(42))
|
||||||
// Simulate this going through interop as raw C pointer.
|
// Simulate this going through interop as raw C pointer.
|
||||||
val pointerValue: Long = mainThreadRef.asCPointer().toLong()
|
val pointerValue: Long = mainThreadRef.asCPointer().toLong()
|
||||||
val future = worker.execute(TransferMode.SAFE, { pointerValue }) {
|
val future = worker.execute(TransferMode.SAFE, { pointerValue }) {
|
||||||
val pointer: COpaquePointer = it.toCPointer()!!
|
val pointer: COpaquePointer = it.toCPointer()!!
|
||||||
assertFailsWith<IncorrectDereferenceException> {
|
if (kotlin.native.Platform.memoryModel == kotlin.native.MemoryModel.EXPERIMENTAL) {
|
||||||
// Even attempting to convert a pointer to StableRef should fail.
|
val otherThreadRef: StableRef<Holder> = pointer.asStableRef()
|
||||||
val otherThreadRef: StableRef<Any> = pointer.asStableRef()
|
assertEquals(otherThreadRef.get().value, 42)
|
||||||
println(otherThreadRef.toString())
|
} else {
|
||||||
|
assertFailsWith<IncorrectDereferenceException> {
|
||||||
|
// Even attempting to convert a pointer to StableRef should fail.
|
||||||
|
val otherThreadRef: StableRef<Holder> = pointer.asStableRef()
|
||||||
|
println(otherThreadRef.get().value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Unit
|
Unit
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,16 @@ val int2 = 77
|
|||||||
int1++
|
int1++
|
||||||
withWorker {
|
withWorker {
|
||||||
executeAfter(0, {
|
executeAfter(0, {
|
||||||
assertFailsWith<IncorrectDereferenceException> {
|
if (kotlin.native.Platform.memoryModel == kotlin.native.MemoryModel.EXPERIMENTAL) {
|
||||||
int1++
|
int1++
|
||||||
|
assertEquals(3, int1)
|
||||||
|
} else {
|
||||||
|
assertFailsWith<IncorrectDereferenceException> {
|
||||||
|
int1++
|
||||||
|
}
|
||||||
|
assertEquals(2, int1)
|
||||||
}
|
}
|
||||||
assertEquals(2, int1)
|
|
||||||
assertEquals(77, int2)
|
assertEquals(77, int2)
|
||||||
}.freeze())
|
}.freeze())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ namespace gc {
|
|||||||
|
|
||||||
using GC = kotlin::gc::NoOpGC;
|
using GC = kotlin::gc::NoOpGC;
|
||||||
|
|
||||||
|
inline constexpr bool kSupportsMultipleMutators = true;
|
||||||
|
|
||||||
} // namespace gc
|
} // namespace gc
|
||||||
} // namespace kotlin
|
} // namespace kotlin
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ namespace gc {
|
|||||||
|
|
||||||
using GC = kotlin::gc::SingleThreadMarkAndSweep;
|
using GC = kotlin::gc::SingleThreadMarkAndSweep;
|
||||||
|
|
||||||
|
inline constexpr bool kSupportsMultipleMutators = false;
|
||||||
|
|
||||||
} // namespace gc
|
} // namespace gc
|
||||||
} // namespace kotlin
|
} // namespace kotlin
|
||||||
|
|
||||||
|
|||||||
@@ -3737,3 +3737,5 @@ kotlin::ThreadState kotlin::GetThreadState(MemoryState* thread) noexcept {
|
|||||||
// Assume that we are always in the Runnable thread state.
|
// Assume that we are always in the Runnable thread state.
|
||||||
return ThreadState::kRunnable;
|
return ThreadState::kRunnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool kotlin::kSupportsMultipleMutators = true;
|
||||||
|
|||||||
@@ -441,6 +441,8 @@ ALWAYS_INLINE inline R CallWithThreadState(R(*function)(Args...), Args... args)
|
|||||||
return function(std::forward<Args>(args)...);
|
return function(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern const bool kSupportsMultipleMutators;
|
||||||
|
|
||||||
} // namespace kotlin
|
} // namespace kotlin
|
||||||
|
|
||||||
#endif // RUNTIME_MEMORY_H
|
#endif // RUNTIME_MEMORY_H
|
||||||
|
|||||||
@@ -107,8 +107,9 @@ RuntimeState* initRuntime() {
|
|||||||
result->memoryState = InitMemory(false); // The argument will be ignored for legacy DestroyRuntimeMode
|
result->memoryState = InitMemory(false); // The argument will be ignored for legacy DestroyRuntimeMode
|
||||||
result->worker = WorkerInit(result->memoryState, true);
|
result->worker = WorkerInit(result->memoryState, true);
|
||||||
firstRuntime = atomicAdd(&aliveRuntimesCount, 1) == 1;
|
firstRuntime = atomicAdd(&aliveRuntimesCount, 1) == 1;
|
||||||
if (CurrentMemoryModel == MemoryModel::kExperimental) {
|
if (!kotlin::kSupportsMultipleMutators && !firstRuntime) {
|
||||||
RuntimeCheck(firstRuntime, "Experimental MM does not support multiple mutator threads yet");
|
konan::consoleErrorf("This GC implementation does not support multiple mutator threads.");
|
||||||
|
konan::abort();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DESTROY_RUNTIME_ON_SHUTDOWN:
|
case DESTROY_RUNTIME_ON_SHUTDOWN:
|
||||||
@@ -120,8 +121,9 @@ RuntimeState* initRuntime() {
|
|||||||
RuntimeAssert(lastStatus != kGlobalRuntimeShutdown, "Kotlin runtime was shut down. Cannot create new runtimes.");
|
RuntimeAssert(lastStatus != kGlobalRuntimeShutdown, "Kotlin runtime was shut down. Cannot create new runtimes.");
|
||||||
}
|
}
|
||||||
firstRuntime = lastStatus == kGlobalRuntimeUninitialized;
|
firstRuntime = lastStatus == kGlobalRuntimeUninitialized;
|
||||||
if (CurrentMemoryModel == MemoryModel::kExperimental) {
|
if (!kotlin::kSupportsMultipleMutators && !firstRuntime) {
|
||||||
RuntimeCheck(firstRuntime, "Experimental MM does not support multiple mutator threads yet");
|
konan::consoleErrorf("This GC implementation does not support multiple mutator threads.");
|
||||||
|
konan::abort();
|
||||||
}
|
}
|
||||||
result->memoryState = InitMemory(firstRuntime);
|
result->memoryState = InitMemory(firstRuntime);
|
||||||
result->worker = WorkerInit(result->memoryState, true);
|
result->worker = WorkerInit(result->memoryState, true);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "Exceptions.h"
|
#include "Exceptions.h"
|
||||||
#include "ExtraObjectData.hpp"
|
#include "ExtraObjectData.hpp"
|
||||||
#include "Freezing.hpp"
|
#include "Freezing.hpp"
|
||||||
|
#include "GC.hpp"
|
||||||
#include "GlobalsRegistry.hpp"
|
#include "GlobalsRegistry.hpp"
|
||||||
#include "InitializationScheme.hpp"
|
#include "InitializationScheme.hpp"
|
||||||
#include "KAssert.h"
|
#include "KAssert.h"
|
||||||
@@ -509,3 +510,5 @@ extern "C" ALWAYS_INLINE RUNTIME_NOTHROW void Kotlin_mm_switchThreadStateRunnabl
|
|||||||
MemoryState* kotlin::mm::GetMemoryState() {
|
MemoryState* kotlin::mm::GetMemoryState() {
|
||||||
return ToMemoryState(ThreadRegistry::Instance().CurrentThreadDataNode());
|
return ToMemoryState(ThreadRegistry::Instance().CurrentThreadDataNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool kotlin::kSupportsMultipleMutators = kotlin::gc::kSupportsMultipleMutators;
|
||||||
|
|||||||
Reference in New Issue
Block a user