diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index c7035ec4c48..4fc07b69956 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -1051,6 +1051,11 @@ internal abstract class FunctionGenerationContext( return exception } + fun generateFrameCheck() { + assert(slotsPhi != null) + call(context.llvm.checkCurrentFrameFunction, listOf(slotsPhi!!)) + } + inline fun ifThenElse( condition: LLVMValueRef, thenValue: LLVMValueRef, diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index 8a46477c411..10afeecab48 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -457,6 +457,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti val enterFrameFunction = importRtFunction("EnterFrame") val leaveFrameFunction = importRtFunction("LeaveFrame") val setCurrentFrameFunction = importRtFunction("SetCurrentFrame") + val checkCurrentFrameFunction = importRtFunction("CheckCurrentFrame") val lookupInterfaceTableRecord = importRtFunction("LookupInterfaceTableRecord") val isInstanceFunction = importRtFunction("IsInstance") val isInstanceOfClassFastFunction = importRtFunction("IsInstanceOfClassFast") diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 27f5ab2cd24..7931779dff4 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -1213,6 +1213,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map(frame); + RuntimeAssert(currentFrame == expectedFrame, "Frame is expected to be %p, but current frame is %p", expectedFrame, currentFrame); +} + RUNTIME_NOTHROW void GC_UnregisterWorker(void* worker) { #if USE_CYCLIC_GC cyclicRemoveWorker(worker, g_hasCyclicCollector); diff --git a/kotlin-native/runtime/src/main/cpp/CompilerExport.cpp b/kotlin-native/runtime/src/main/cpp/CompilerExport.cpp index cb997680b26..83ab6969123 100644 --- a/kotlin-native/runtime/src/main/cpp/CompilerExport.cpp +++ b/kotlin-native/runtime/src/main/cpp/CompilerExport.cpp @@ -36,6 +36,7 @@ void EnsureDeclarationsEmitted() { ensureUsed(EnterFrame); ensureUsed(LeaveFrame); ensureUsed(SetCurrentFrame); + ensureUsed(CheckCurrentFrame); ensureUsed(AddTLSRecord); ensureUsed(LookupTLS); ensureUsed(MutationCheck); diff --git a/kotlin-native/runtime/src/main/cpp/Memory.h b/kotlin-native/runtime/src/main/cpp/Memory.h index df91eb9a59d..f7f50ed94be 100644 --- a/kotlin-native/runtime/src/main/cpp/Memory.h +++ b/kotlin-native/runtime/src/main/cpp/Memory.h @@ -246,6 +246,7 @@ void LeaveFrame(ObjHeader** start, int parameters, int count) RUNTIME_NOTHROW; // Set current frame in case if exception caught. void SetCurrentFrame(ObjHeader** start) RUNTIME_NOTHROW; FrameOverlay* getCurrentFrame() RUNTIME_NOTHROW; +ALWAYS_INLINE void CheckCurrentFrame(ObjHeader** frame) RUNTIME_NOTHROW; // Clears object subgraph references from memory subsystem, and optionally // checks if subgraph referenced by given root is disjoint from the rest of diff --git a/kotlin-native/runtime/src/mm/cpp/Memory.cpp b/kotlin-native/runtime/src/mm/cpp/Memory.cpp index 4c6f2e54d93..42656d051ae 100644 --- a/kotlin-native/runtime/src/mm/cpp/Memory.cpp +++ b/kotlin-native/runtime/src/mm/cpp/Memory.cpp @@ -250,6 +250,12 @@ extern "C" RUNTIME_NOTHROW FrameOverlay* getCurrentFrame() { return threadData->shadowStack().getCurrentFrame(); } +extern "C" RUNTIME_NOTHROW ALWAYS_INLINE void CheckCurrentFrame(ObjHeader** frame) { + auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData(); + AssertThreadState(threadData, ThreadState::kRunnable); + return threadData->shadowStack().checkCurrentFrame(reinterpret_cast(frame)); +} + extern "C" RUNTIME_NOTHROW void AddTLSRecord(MemoryState* memory, void** key, int size) { memory->GetThreadData()->tls().AddRecord(key, size); } diff --git a/kotlin-native/runtime/src/mm/cpp/ShadowStack.cpp b/kotlin-native/runtime/src/mm/cpp/ShadowStack.cpp index 5fc76479efa..ba543b06d44 100644 --- a/kotlin-native/runtime/src/mm/cpp/ShadowStack.cpp +++ b/kotlin-native/runtime/src/mm/cpp/ShadowStack.cpp @@ -43,3 +43,7 @@ void mm::ShadowStack::SetCurrentFrame(ObjHeader** start) noexcept { FrameOverlay* mm::ShadowStack::getCurrentFrame() noexcept { return currentFrame_; } + +void mm::ShadowStack::checkCurrentFrame(FrameOverlay* frame) noexcept { + RuntimeAssert(currentFrame_ == frame, "Frame is expected to be %p, but current frame is %p", frame, currentFrame_); +} \ No newline at end of file diff --git a/kotlin-native/runtime/src/mm/cpp/ShadowStack.hpp b/kotlin-native/runtime/src/mm/cpp/ShadowStack.hpp index 2f9980ed29f..4622bd7fa00 100644 --- a/kotlin-native/runtime/src/mm/cpp/ShadowStack.hpp +++ b/kotlin-native/runtime/src/mm/cpp/ShadowStack.hpp @@ -55,6 +55,7 @@ public: void LeaveFrame(ObjHeader** start, int parameters, int count) noexcept; void SetCurrentFrame(ObjHeader** start) noexcept; FrameOverlay* getCurrentFrame() noexcept; + void checkCurrentFrame(FrameOverlay* frame) noexcept; Iterator begin() noexcept { return Iterator(currentFrame_); } Iterator end() noexcept { return Iterator(nullptr); }