From 05d4bbf3678e165706eed319284bb959293b0b50 Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Mon, 15 Feb 2021 10:25:28 +0300 Subject: [PATCH] Do not generate safepoints for initializer functions (#4700) --- .../kotlin/backend/konan/llvm/CodeGenerator.kt | 16 +++++++++++++--- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 4 ++++ .../llvm/objcexport/ObjCExportCodeGenerator.kt | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) 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 3fa91b65d85..48ca2a89b60 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 @@ -350,6 +350,13 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, // for example. var needsRuntimeInit = false + // Marks that function is not allowed to call into Kotlin runtime. For this function no safepoints, no enter/leave + // frames are generated. + // TODO: Should forbid all calls into runtime except for explicitly allowed. Also should impose the same restriction + // on function being called from this one. + // TODO: Consider using a different abstraction than `FunctionGenerationContext`. + var forbidRuntime = false + init { irFunction?.let { if (!irFunction.isExported()) { @@ -1221,6 +1228,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, internal fun epilogue() { appendingTo(prologueBb) { if (needsRuntimeInit) { + check(!forbidRuntime) { "Attempt to init runtime where runtime usage is forbidden" } call(context.llvm.initRuntimeIfNeeded, emptyList()) } val slots = if (needSlotsPhi) @@ -1228,6 +1236,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, else kNullObjHeaderPtrPtr if (needSlots) { + check(!forbidRuntime) { "Attempt to start a frame where runtime usage is forbidden" } // Zero-init slots. val slotsMem = bitcast(kInt8Ptr, slots) call(context.llvm.memsetFunction, @@ -1267,7 +1276,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, returnType == voidType -> { releaseVars() assert(returnSlot == null) - if (context.memoryModel == MemoryModel.EXPERIMENTAL) + if (!forbidRuntime && context.memoryModel == MemoryModel.EXPERIMENTAL) call(context.llvm.Kotlin_mm_safePointFunctionEpilogue, emptyList()) LLVMBuildRetVoid(builder) } @@ -1278,7 +1287,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, updateReturnRef(returnPhi, returnSlot!!) } releaseVars() - if (context.memoryModel == MemoryModel.EXPERIMENTAL) + if (!forbidRuntime && context.memoryModel == MemoryModel.EXPERIMENTAL) call(context.llvm.Kotlin_mm_safePointFunctionEpilogue, emptyList()) LLVMBuildRet(builder, returnPhi) } @@ -1320,7 +1329,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, } releaseVars() - if (context.memoryModel == MemoryModel.EXPERIMENTAL) + if (!forbidRuntime && context.memoryModel == MemoryModel.EXPERIMENTAL) call(context.llvm.Kotlin_mm_safePointExceptionUnwind, emptyList()) LLVMBuildResume(builder, landingpad) } @@ -1452,6 +1461,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, private fun releaseVars() { if (needSlots) { + check(!forbidRuntime) { "Attempt to leave a frame where runtime usage is forbidden" } call(context.llvm.leaveFrameFunction, listOf(slotsPhi!!, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm)) } 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 49a6facbce4..d2796f57542 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 @@ -513,6 +513,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map) { generateFunction(codegen, ctorFunction) { + forbidRuntime = true val initGuardName = ctorFunction.name.orEmpty() + "_guard" val initGuard = LLVMAddGlobal(context.llvmModule, int32Type, initGuardName) LLVMSetInitializer(initGuard, kImmZero) @@ -2558,6 +2561,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map store(value.llvm, global) }