[K/N] Replaced safe points to prologue
This commit is contained in:
+22
-23
@@ -434,7 +434,7 @@ internal abstract class FunctionGenerationContext(
|
|||||||
val codegen: CodeGenerator,
|
val codegen: CodeGenerator,
|
||||||
private val startLocation: LocationInfo?,
|
private val startLocation: LocationInfo?,
|
||||||
private val endLocation: LocationInfo?,
|
private val endLocation: LocationInfo?,
|
||||||
private val switchToRunnable: Boolean,
|
switchToRunnable: Boolean,
|
||||||
internal val irFunction: IrFunction? = null
|
internal val irFunction: IrFunction? = null
|
||||||
) : ContextUtils {
|
) : ContextUtils {
|
||||||
|
|
||||||
@@ -480,10 +480,13 @@ internal abstract class FunctionGenerationContext(
|
|||||||
protected open val needCleanupLandingpadAndLeaveFrame: Boolean
|
protected open val needCleanupLandingpadAndLeaveFrame: Boolean
|
||||||
get() = irFunction?.annotations?.hasAnnotation(RuntimeNames.exportForCppRuntime) == true || // Exported to foreign code
|
get() = irFunction?.annotations?.hasAnnotation(RuntimeNames.exportForCppRuntime) == true || // Exported to foreign code
|
||||||
(!stackLocalsManager.isEmpty() && context.memoryModel != MemoryModel.EXPERIMENTAL) ||
|
(!stackLocalsManager.isEmpty() && context.memoryModel != MemoryModel.EXPERIMENTAL) ||
|
||||||
(context.memoryModel == MemoryModel.EXPERIMENTAL && switchToRunnable)
|
switchToRunnable
|
||||||
|
|
||||||
private var setCurrentFrameIsCalled: Boolean = false
|
private var setCurrentFrameIsCalled: Boolean = false
|
||||||
|
|
||||||
|
private val switchToRunnable: Boolean =
|
||||||
|
context.memoryModel == MemoryModel.EXPERIMENTAL && switchToRunnable
|
||||||
|
|
||||||
val stackLocalsManager = StackLocalsManagerImpl(this, stackLocalsInitBb)
|
val stackLocalsManager = StackLocalsManagerImpl(this, stackLocalsInitBb)
|
||||||
|
|
||||||
data class FunctionInvokeInformation(
|
data class FunctionInvokeInformation(
|
||||||
@@ -910,11 +913,6 @@ internal abstract class FunctionGenerationContext(
|
|||||||
}
|
}
|
||||||
call(context.llvm.setCurrentFrameFunction, listOf(slotsPhi!!))
|
call(context.llvm.setCurrentFrameFunction, listOf(slotsPhi!!))
|
||||||
setCurrentFrameIsCalled = true
|
setCurrentFrameIsCalled = true
|
||||||
if (context.memoryModel == MemoryModel.EXPERIMENTAL) {
|
|
||||||
if (!forbidRuntime) {
|
|
||||||
call(context.llvm.Kotlin_mm_safePointExceptionUnwind, emptyList())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return landingpad
|
return landingpad
|
||||||
}
|
}
|
||||||
@@ -1502,7 +1500,7 @@ internal abstract class FunctionGenerationContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
releaseVars()
|
releaseVars()
|
||||||
handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointExceptionUnwind)
|
handleEpilogueExperimentalMM()
|
||||||
LLVMBuildResume(builder, landingpad)
|
LLVMBuildResume(builder, landingpad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1514,14 +1512,11 @@ internal abstract class FunctionGenerationContext(
|
|||||||
* places with inconsistent stack layout. So we setup debug info only for this part of bb.
|
* places with inconsistent stack layout. So we setup debug info only for this part of bb.
|
||||||
*/
|
*/
|
||||||
startLocation?.let { debugLocation(it, it) }
|
startLocation?.let { debugLocation(it, it) }
|
||||||
val needStateSwitch = context.memoryModel == MemoryModel.EXPERIMENTAL && switchToRunnable
|
if (needsRuntimeInit || switchToRunnable) {
|
||||||
if (needsRuntimeInit || needStateSwitch) {
|
|
||||||
check(!forbidRuntime) { "Attempt to init runtime where runtime usage is forbidden" }
|
check(!forbidRuntime) { "Attempt to init runtime where runtime usage is forbidden" }
|
||||||
call(context.llvm.initRuntimeIfNeeded, emptyList())
|
call(context.llvm.initRuntimeIfNeeded, emptyList())
|
||||||
}
|
}
|
||||||
if (needStateSwitch) {
|
handlePrologueExperimentalMM()
|
||||||
switchThreadState(Runnable)
|
|
||||||
}
|
|
||||||
if (needSlots || needCleanupLandingpadAndLeaveFrame) {
|
if (needSlots || needCleanupLandingpadAndLeaveFrame) {
|
||||||
call(context.llvm.enterFrameFunction, listOf(slotsPhi!!, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm))
|
call(context.llvm.enterFrameFunction, listOf(slotsPhi!!, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm))
|
||||||
} else {
|
} else {
|
||||||
@@ -1577,18 +1572,22 @@ internal abstract class FunctionGenerationContext(
|
|||||||
|
|
||||||
protected fun onReturn() {
|
protected fun onReturn() {
|
||||||
releaseVars()
|
releaseVars()
|
||||||
handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointFunctionEpilogue)
|
handleEpilogueExperimentalMM()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleEpilogueForExperimentalMM(safePointFunction: LlvmCallable) {
|
private fun handlePrologueExperimentalMM() {
|
||||||
if (context.memoryModel == MemoryModel.EXPERIMENTAL) {
|
if (switchToRunnable) {
|
||||||
if (!forbidRuntime) {
|
switchThreadState(Runnable)
|
||||||
call(safePointFunction, emptyList())
|
}
|
||||||
}
|
if (context.memoryModel == MemoryModel.EXPERIMENTAL && !forbidRuntime) {
|
||||||
if (switchToRunnable) {
|
call(context.llvm.Kotlin_mm_safePointFunctionPrologue, emptyList())
|
||||||
check(!forbidRuntime) { "Generating a bridge when runtime is forbidden" }
|
}
|
||||||
switchThreadState(Native)
|
}
|
||||||
}
|
|
||||||
|
private fun handleEpilogueExperimentalMM() {
|
||||||
|
if (switchToRunnable) {
|
||||||
|
check(!forbidRuntime) { "Generating a bridge when runtime is forbidden" }
|
||||||
|
switchThreadState(Native)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -507,9 +507,8 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
|
|||||||
private val Kotlin_ObjCExport_NSIntegerTypeProvider by lazyRtFunction
|
private val Kotlin_ObjCExport_NSIntegerTypeProvider by lazyRtFunction
|
||||||
private val Kotlin_longTypeProvider by lazyRtFunction
|
private val Kotlin_longTypeProvider by lazyRtFunction
|
||||||
|
|
||||||
val Kotlin_mm_safePointFunctionEpilogue by lazyRtFunction
|
val Kotlin_mm_safePointFunctionPrologue by lazyRtFunction
|
||||||
val Kotlin_mm_safePointWhileLoopBody by lazyRtFunction
|
val Kotlin_mm_safePointWhileLoopBody by lazyRtFunction
|
||||||
val Kotlin_mm_safePointExceptionUnwind by lazyRtFunction
|
|
||||||
|
|
||||||
val tlsMode by lazy {
|
val tlsMode by lazy {
|
||||||
when (target) {
|
when (target) {
|
||||||
|
|||||||
@@ -67,9 +67,8 @@ public:
|
|||||||
|
|
||||||
class GCSchedulerThreadData {
|
class GCSchedulerThreadData {
|
||||||
public:
|
public:
|
||||||
static constexpr size_t kFunctionEpilogueWeight = 1;
|
static constexpr size_t kFunctionPrologueWeight = 1;
|
||||||
static constexpr size_t kLoopBodyWeight = 1;
|
static constexpr size_t kLoopBodyWeight = 1;
|
||||||
static constexpr size_t kExceptionUnwindWeight = 1;
|
|
||||||
|
|
||||||
explicit GCSchedulerThreadData(GCSchedulerConfig& config, std::function<void(GCSchedulerThreadData&)> onSafePoint) noexcept :
|
explicit GCSchedulerThreadData(GCSchedulerConfig& config, std::function<void(GCSchedulerThreadData&)> onSafePoint) noexcept :
|
||||||
config_(config), onSafePoint_(std::move(onSafePoint)) {
|
config_(config), onSafePoint_(std::move(onSafePoint)) {
|
||||||
|
|||||||
@@ -33,9 +33,8 @@ public:
|
|||||||
explicit ThreadData(NoOpGC& gc, mm::ThreadData& threadData) noexcept {}
|
explicit ThreadData(NoOpGC& gc, mm::ThreadData& threadData) noexcept {}
|
||||||
~ThreadData() = default;
|
~ThreadData() = default;
|
||||||
|
|
||||||
void SafePointFunctionEpilogue() noexcept {}
|
void SafePointFunctionPrologue() noexcept {}
|
||||||
void SafePointLoopBody() noexcept {}
|
void SafePointLoopBody() noexcept {}
|
||||||
void SafePointExceptionUnwind() noexcept {}
|
|
||||||
void SafePointAllocation(size_t size) noexcept {}
|
void SafePointAllocation(size_t size) noexcept {}
|
||||||
|
|
||||||
void PerformFullGC() noexcept {}
|
void PerformFullGC() noexcept {}
|
||||||
|
|||||||
@@ -64,18 +64,14 @@ std::atomic<gc::SameThreadMarkAndSweep::SafepointFlag> gSafepointFlag = gc::Same
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ALWAYS_INLINE void gc::SameThreadMarkAndSweep::ThreadData::SafePointFunctionEpilogue() noexcept {
|
ALWAYS_INLINE void gc::SameThreadMarkAndSweep::ThreadData::SafePointFunctionPrologue() noexcept {
|
||||||
SafePointRegular(GCSchedulerThreadData::kFunctionEpilogueWeight);
|
SafePointRegular(GCSchedulerThreadData::kFunctionPrologueWeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void gc::SameThreadMarkAndSweep::ThreadData::SafePointLoopBody() noexcept {
|
ALWAYS_INLINE void gc::SameThreadMarkAndSweep::ThreadData::SafePointLoopBody() noexcept {
|
||||||
SafePointRegular(GCSchedulerThreadData::kLoopBodyWeight);
|
SafePointRegular(GCSchedulerThreadData::kLoopBodyWeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void gc::SameThreadMarkAndSweep::ThreadData::SafePointExceptionUnwind() noexcept {
|
|
||||||
SafePointRegular(GCSchedulerThreadData::kExceptionUnwindWeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gc::SameThreadMarkAndSweep::ThreadData::SafePointAllocation(size_t size) noexcept {
|
void gc::SameThreadMarkAndSweep::ThreadData::SafePointAllocation(size_t size) noexcept {
|
||||||
threadData_.gcScheduler().OnSafePointAllocation(size);
|
threadData_.gcScheduler().OnSafePointAllocation(size);
|
||||||
SafepointFlag flag = gSafepointFlag.load();
|
SafepointFlag flag = gSafepointFlag.load();
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public:
|
|||||||
explicit ThreadData(SameThreadMarkAndSweep& gc, mm::ThreadData& threadData) noexcept : gc_(gc), threadData_(threadData) {}
|
explicit ThreadData(SameThreadMarkAndSweep& gc, mm::ThreadData& threadData) noexcept : gc_(gc), threadData_(threadData) {}
|
||||||
~ThreadData() = default;
|
~ThreadData() = default;
|
||||||
|
|
||||||
void SafePointFunctionEpilogue() noexcept;
|
void SafePointFunctionPrologue() noexcept;
|
||||||
void SafePointLoopBody() noexcept;
|
void SafePointLoopBody() noexcept;
|
||||||
void SafePointExceptionUnwind() noexcept;
|
void SafePointExceptionUnwind() noexcept;
|
||||||
void SafePointAllocation(size_t size) noexcept;
|
void SafePointAllocation(size_t size) noexcept;
|
||||||
|
|||||||
@@ -785,7 +785,7 @@ TEST_F(SameThreadMarkAndSweepTest, MultipleMutatorsCollect) {
|
|||||||
|
|
||||||
for (int i = 1; i < kDefaultThreadCount; ++i) {
|
for (int i = 1; i < kDefaultThreadCount; ++i) {
|
||||||
gcFutures[i] =
|
gcFutures[i] =
|
||||||
mutators[i].Execute([](mm::ThreadData& threadData, Mutator& mutator) { threadData.gc().SafePointFunctionEpilogue(); });
|
mutators[i].Execute([](mm::ThreadData& threadData, Mutator& mutator) { threadData.gc().SafePointFunctionPrologue(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& future : gcFutures) {
|
for (auto& future : gcFutures) {
|
||||||
@@ -906,7 +906,7 @@ TEST_F(SameThreadMarkAndSweepTest, MultipleMutatorsAddToRootSetAfterCollectionRe
|
|||||||
for (int i = 1; i < kDefaultThreadCount; ++i) {
|
for (int i = 1; i < kDefaultThreadCount; ++i) {
|
||||||
gcFutures[i] = mutators[i].Execute([i, expandRootSet](mm::ThreadData& threadData, Mutator& mutator) {
|
gcFutures[i] = mutators[i].Execute([i, expandRootSet](mm::ThreadData& threadData, Mutator& mutator) {
|
||||||
expandRootSet(threadData, mutator, i);
|
expandRootSet(threadData, mutator, i);
|
||||||
threadData.gc().SafePointFunctionEpilogue();
|
threadData.gc().SafePointFunctionPrologue();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -970,7 +970,7 @@ TEST_F(SameThreadMarkAndSweepTest, CrossThreadReference) {
|
|||||||
|
|
||||||
for (int i = 1; i < kDefaultThreadCount; ++i) {
|
for (int i = 1; i < kDefaultThreadCount; ++i) {
|
||||||
gcFutures[i] =
|
gcFutures[i] =
|
||||||
mutators[i].Execute([](mm::ThreadData& threadData, Mutator& mutator) { threadData.gc().SafePointFunctionEpilogue(); });
|
mutators[i].Execute([](mm::ThreadData& threadData, Mutator& mutator) { threadData.gc().SafePointFunctionPrologue(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& future : gcFutures) {
|
for (auto& future : gcFutures) {
|
||||||
@@ -1034,7 +1034,7 @@ TEST_F(SameThreadMarkAndSweepTest, MultipleMutatorsWeaks) {
|
|||||||
|
|
||||||
for (int i = 1; i < kDefaultThreadCount; ++i) {
|
for (int i = 1; i < kDefaultThreadCount; ++i) {
|
||||||
gcFutures[i] = mutators[i].Execute([weak](mm::ThreadData& threadData, Mutator& mutator) {
|
gcFutures[i] = mutators[i].Execute([weak](mm::ThreadData& threadData, Mutator& mutator) {
|
||||||
threadData.gc().SafePointFunctionEpilogue();
|
threadData.gc().SafePointFunctionPrologue();
|
||||||
EXPECT_THAT((*weak)->referred, nullptr);
|
EXPECT_THAT((*weak)->referred, nullptr);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1092,7 +1092,7 @@ TEST_F(SameThreadMarkAndSweepTest, NewThreadsWhileRequestingCollection) {
|
|||||||
// All the other threads are stopping at safe points.
|
// All the other threads are stopping at safe points.
|
||||||
for (int i = 1; i < kDefaultThreadCount; ++i) {
|
for (int i = 1; i < kDefaultThreadCount; ++i) {
|
||||||
gcFutures[i] =
|
gcFutures[i] =
|
||||||
mutators[i].Execute([](mm::ThreadData& threadData, Mutator& mutator) { threadData.gc().SafePointFunctionEpilogue(); });
|
mutators[i].Execute([](mm::ThreadData& threadData, Mutator& mutator) { threadData.gc().SafePointFunctionPrologue(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// GC will be completed first
|
// GC will be completed first
|
||||||
|
|||||||
@@ -3733,7 +3733,7 @@ ALWAYS_INLINE RUNTIME_NOTHROW void Kotlin_mm_switchThreadStateRunnable() {
|
|||||||
// no-op, used by the new MM only.
|
// no-op, used by the new MM only.
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE RUNTIME_NOTHROW void Kotlin_mm_safePointFunctionEpilogue() {
|
ALWAYS_INLINE RUNTIME_NOTHROW void Kotlin_mm_safePointFunctionPrologue() {
|
||||||
// no-op, used by the new MM only.
|
// no-op, used by the new MM only.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3741,10 +3741,6 @@ ALWAYS_INLINE RUNTIME_NOTHROW void Kotlin_mm_safePointWhileLoopBody() {
|
|||||||
// no-op, used by the new MM only.
|
// no-op, used by the new MM only.
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE RUNTIME_NOTHROW void Kotlin_mm_safePointExceptionUnwind() {
|
|
||||||
// no-op, used by the new MM only.
|
|
||||||
}
|
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
#if !KONAN_NO_EXCEPTIONS
|
#if !KONAN_NO_EXCEPTIONS
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ void EnsureDeclarationsEmitted() {
|
|||||||
ensureUsed(CheckGlobalsAccessible);
|
ensureUsed(CheckGlobalsAccessible);
|
||||||
ensureUsed(Kotlin_mm_switchThreadStateNative);
|
ensureUsed(Kotlin_mm_switchThreadStateNative);
|
||||||
ensureUsed(Kotlin_mm_switchThreadStateRunnable);
|
ensureUsed(Kotlin_mm_switchThreadStateRunnable);
|
||||||
ensureUsed(Kotlin_mm_safePointFunctionEpilogue);
|
ensureUsed(Kotlin_mm_safePointFunctionPrologue);
|
||||||
ensureUsed(Kotlin_mm_safePointWhileLoopBody);
|
ensureUsed(Kotlin_mm_safePointWhileLoopBody);
|
||||||
ensureUsed(Kotlin_mm_safePointExceptionUnwind);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -332,9 +332,8 @@ ALWAYS_INLINE RUNTIME_NOTHROW void Kotlin_mm_switchThreadStateNative();
|
|||||||
ALWAYS_INLINE RUNTIME_NOTHROW void Kotlin_mm_switchThreadStateRunnable();
|
ALWAYS_INLINE RUNTIME_NOTHROW void Kotlin_mm_switchThreadStateRunnable();
|
||||||
|
|
||||||
// Safe point callbacks from Kotlin code generator.
|
// Safe point callbacks from Kotlin code generator.
|
||||||
void Kotlin_mm_safePointFunctionEpilogue() RUNTIME_NOTHROW;
|
void Kotlin_mm_safePointFunctionPrologue() RUNTIME_NOTHROW;
|
||||||
void Kotlin_mm_safePointWhileLoopBody() RUNTIME_NOTHROW;
|
void Kotlin_mm_safePointWhileLoopBody() RUNTIME_NOTHROW;
|
||||||
void Kotlin_mm_safePointExceptionUnwind() RUNTIME_NOTHROW;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -533,10 +533,10 @@ extern "C" void CheckGlobalsAccessible() {
|
|||||||
// Always accessible
|
// Always accessible
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" RUNTIME_NOTHROW ALWAYS_INLINE void Kotlin_mm_safePointFunctionEpilogue() {
|
extern "C" RUNTIME_NOTHROW ALWAYS_INLINE void Kotlin_mm_safePointFunctionPrologue() {
|
||||||
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
|
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
|
||||||
AssertThreadState(threadData, ThreadState::kRunnable);
|
AssertThreadState(threadData, ThreadState::kRunnable);
|
||||||
threadData->gc().SafePointFunctionEpilogue();
|
threadData->gc().SafePointFunctionPrologue();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" RUNTIME_NOTHROW ALWAYS_INLINE void Kotlin_mm_safePointWhileLoopBody() {
|
extern "C" RUNTIME_NOTHROW ALWAYS_INLINE void Kotlin_mm_safePointWhileLoopBody() {
|
||||||
@@ -545,12 +545,6 @@ extern "C" RUNTIME_NOTHROW ALWAYS_INLINE void Kotlin_mm_safePointWhileLoopBody()
|
|||||||
threadData->gc().SafePointLoopBody();
|
threadData->gc().SafePointLoopBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" RUNTIME_NOTHROW ALWAYS_INLINE void Kotlin_mm_safePointExceptionUnwind() {
|
|
||||||
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
|
|
||||||
AssertThreadState(threadData, ThreadState::kRunnable);
|
|
||||||
threadData->gc().SafePointExceptionUnwind();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" ALWAYS_INLINE RUNTIME_NOTHROW void Kotlin_mm_switchThreadStateNative() {
|
extern "C" ALWAYS_INLINE RUNTIME_NOTHROW void Kotlin_mm_switchThreadStateNative() {
|
||||||
SwitchThreadState(mm::ThreadRegistry::Instance().CurrentThreadData(), ThreadState::kNative);
|
SwitchThreadState(mm::ThreadRegistry::Instance().CurrentThreadData(), ThreadState::kNative);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user