diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 4ac56fd8e7a..aec2e658db4 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -73,21 +73,6 @@ val IrField.isMainOnlyNonPrimitive get() = when { else -> storageKind == FieldStorageKind.MAIN_THREAD } -internal fun verifyModule(llvmModule: LLVMModuleRef, current: String = "") { - memScoped { - val errorRef = allocPointerTo() - val verificationResult = LLVMVerifyModule( - llvmModule, LLVMVerifierFailureAction.LLVMPrintMessageAction, errorRef.ptr) - LLVMDisposeMessage(errorRef.value) - if (verificationResult == 1) { - if (current.isNotEmpty()) - println("Error in $current") - LLVMDumpModule(llvmModule) - throw Error("Invalid module") - } - } -} - internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid { val generator = RTTIGenerator(context) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/VerifyModule.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/VerifyModule.kt new file mode 100644 index 00000000000..b67b3bfd674 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/VerifyModule.kt @@ -0,0 +1,95 @@ +package org.jetbrains.kotlin.backend.konan.llvm + +import kotlinx.cinterop.* +import llvm.* +import java.io.File + +internal fun verifyModule(llvmModule: LLVMModuleRef, current: String = "") = memScoped { + val errorRef = allocPointerTo() + errorRef.value = null + + val verificationResult = LLVMVerifyModule( + llvmModule, + LLVMVerifierFailureAction.LLVMReturnStatusAction, + errorRef.ptr + ) + + val verificationError = convertAndDisposeLlvmMessage(errorRef.value) + + if (verificationResult != 0) { + throwModuleVerificationError(llvmModule, current, verificationError) + } +} + +private fun throwModuleVerificationError( + llvmModule: LLVMModuleRef, + current: String, + verificationError: String? +): Nothing { + val exceptionMessage = buildString { + try { + appendModuleVerificationFailureDetails(llvmModule, current, verificationError) + } catch (e: Throwable) { + appendLine("Failed to make full error message: ${e.message}") + } + } + + throw Error(exceptionMessage) +} + +private fun StringBuilder.appendModuleVerificationFailureDetails( + llvmModule: LLVMModuleRef, + current: String, + verificationError: String? +) { + appendLine("Invalid LLVM module") + + if (current.isNotEmpty()) + appendLine("Error in $current") + + appendVerificationError(verificationError) + + val moduleDumpFile = createTempFile("kotlin_native_llvm_module_dump", ".ll") + + dumpModuleAndAppendDetails(llvmModule, moduleDumpFile) + + moduleDumpFile.appendText(verificationError.orEmpty()) +} + +private fun StringBuilder.appendVerificationError(error: String?) { + if (error == null) return + + val lines = error.lines() + appendLine("Verification errors:") + + val maxLines = 12 + + lines.take(maxLines).forEach { + appendLine(" $it") + } + + if (lines.size > maxLines) { + appendLine(" ... (full error is available at the LLVM module dump file)") + } +} + +private fun StringBuilder.dumpModuleAndAppendDetails(llvmModule: LLVMModuleRef, moduleDumpFile: File) = memScoped { + val errorRef = allocPointerTo() + errorRef.value = null + val printedWithErrors = LLVMPrintModuleToFile(llvmModule, moduleDumpFile.absolutePath, errorRef.ptr) + + appendLine() + appendLine("LLVM module dump: ${moduleDumpFile.absolutePath}") + + val modulePrintError = convertAndDisposeLlvmMessage(errorRef.value) + if (printedWithErrors != 0) { + appendLine(" (printed with errors: $modulePrintError)") + } +} + +private fun convertAndDisposeLlvmMessage(message: CPointer?): String? = + try { + message?.toKString() + } finally { + LLVMDisposeMessage(message) + }