From 3411ce2e8cb540f2515eca50d3152dec860881cd Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Wed, 22 Feb 2017 14:09:44 +0700 Subject: [PATCH] Interop, backend: refactor and reorder interop lowering * Do not break type compatibility when lowering interop intrinsics. * Place interop lowering before callable reference lowering. * Add other improvements to interop implementation. --- .../nativeInteropStubs/kotlin/clang/Clang.kt | 104 +++++++++--------- .../kotlin/kotlinx/cinterop/JvmCallbacks.kt | 4 +- .../jvm/kotlin/kotlinx/cinterop/JvmTypes.kt | 17 ++- .../src/main/kotlin/kotlinx/cinterop/Types.kt | 49 ++------- .../src/main/kotlin/kotlinx/cinterop/Utils.kt | 4 +- .../kotlin/kotlinx/cinterop/NativeMem.kt | 2 +- .../kotlin/kotlinx/cinterop/NativeTypes.kt | 10 +- .../native/interop/gen/jvm/StubGenerator.kt | 2 +- .../kotlin/backend/konan/InteropUtils.kt | 17 ++- .../kotlin/backend/konan/KonanLower.kt | 6 +- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 3 + .../backend/konan/lower/InteropLowering.kt | 15 ++- 12 files changed, 118 insertions(+), 115 deletions(-) diff --git a/Interop/Indexer/prebuilt/nativeInteropStubs/kotlin/clang/Clang.kt b/Interop/Indexer/prebuilt/nativeInteropStubs/kotlin/clang/Clang.kt index 813a6f3f8a0..2fb0a41a44b 100644 --- a/Interop/Indexer/prebuilt/nativeInteropStubs/kotlin/clang/Clang.kt +++ b/Interop/Indexer/prebuilt/nativeInteropStubs/kotlin/clang/Clang.kt @@ -5,7 +5,7 @@ import kotlinx.cinterop.* fun asctime(arg0: CPointer?): CPointer? { val _arg0 = arg0.rawValue val res = externals.asctime(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clock(): clock_t { @@ -16,7 +16,7 @@ fun clock(): clock_t { fun ctime(arg0: CPointer?): CPointer? { val _arg0 = arg0.rawValue val res = externals.ctime(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun difftime(arg0: time_t, arg1: time_t): Double { @@ -30,20 +30,20 @@ fun getdate(arg0: String?): CPointer? { return memScoped { val _arg0 = arg0?.toCString(memScope).rawPtr val res = externals.getdate(_arg0) - CPointer.createNullable(res) + interpretCPointer(res) } } fun gmtime(arg0: CPointer?): CPointer? { val _arg0 = arg0.rawValue val res = externals.gmtime(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun localtime(arg0: CPointer?): CPointer? { val _arg0 = arg0.rawValue val res = externals.localtime(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun mktime(arg0: CPointer?): time_t { @@ -69,7 +69,7 @@ fun strptime(arg0: String?, arg1: String?, arg2: CPointer?): CPointer(res) + interpretCPointer(res) } } @@ -89,7 +89,7 @@ fun asctime_r(arg0: CPointer?, arg1: String?): CPointer? { val _arg0 = arg0.rawValue val _arg1 = arg1?.toCString(memScope).rawPtr val res = externals.asctime_r(_arg0, _arg1) - CPointer.createNullable(res) + interpretCPointer(res) } } @@ -98,7 +98,7 @@ fun ctime_r(arg0: CPointer?, arg1: String?): CPointer? { val _arg0 = arg0.rawValue val _arg1 = arg1?.toCString(memScope).rawPtr val res = externals.ctime_r(_arg0, _arg1) - CPointer.createNullable(res) + interpretCPointer(res) } } @@ -106,14 +106,14 @@ fun gmtime_r(arg0: CPointer?, arg1: CPointer?): CPointer? { val _arg0 = arg0.rawValue val _arg1 = arg1.rawValue val res = externals.gmtime_r(_arg0, _arg1) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun localtime_r(arg0: CPointer?, arg1: CPointer?): CPointer? { val _arg0 = arg0.rawValue val _arg1 = arg1.rawValue val res = externals.localtime_r(_arg0, _arg1) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun posix2time(arg0: time_t): time_t { @@ -182,7 +182,7 @@ fun clock_settime(__clock_id: clockid_t, __tp: CPointer?): Int { fun clang_getCString(string: CXString): CPointer? { val _string = string.rawPtr val res = externals.clang_getCString(_string) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_disposeString(string: CXString): Unit { @@ -205,7 +205,7 @@ fun clang_getBuildSessionTimestamp(): Long { fun clang_VirtualFileOverlay_create(options: Int): CXVirtualFileOverlay? { val _options = options val res = externals.clang_VirtualFileOverlay_create(_options) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_VirtualFileOverlay_addFileMapping(arg0: CXVirtualFileOverlay?, virtualPath: String?, realPath: String?): CXErrorCode { @@ -249,7 +249,7 @@ fun clang_VirtualFileOverlay_dispose(arg0: CXVirtualFileOverlay?): Unit { fun clang_ModuleMapDescriptor_create(options: Int): CXModuleMapDescriptor? { val _options = options val res = externals.clang_ModuleMapDescriptor_create(_options) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_ModuleMapDescriptor_setFrameworkModuleName(arg0: CXModuleMapDescriptor?, name: String?): CXErrorCode { @@ -289,7 +289,7 @@ fun clang_createIndex(excludeDeclarationsFromPCH: Int, displayDiagnostics: Int): val _excludeDeclarationsFromPCH = excludeDeclarationsFromPCH val _displayDiagnostics = displayDiagnostics val res = externals.clang_createIndex(_excludeDeclarationsFromPCH, _displayDiagnostics) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_disposeIndex(index: CXIndex?): Unit { @@ -343,7 +343,7 @@ fun clang_getFile(tu: CXTranslationUnit?, file_name: String?): CXFile? { val _tu = tu.rawValue val _file_name = file_name?.toCString(memScope).rawPtr val res = externals.clang_getFile(_tu, _file_name) - CPointer.createNullable(res) + interpretCPointer(res) } } @@ -492,7 +492,7 @@ fun clang_getSkippedRanges(tu: CXTranslationUnit?, file: CXFile?): CPointer(res) + return interpretCPointer(res) } fun clang_disposeSourceRangeList(ranges: CPointer?): Unit { @@ -511,7 +511,7 @@ fun clang_getDiagnosticInSet(Diags: CXDiagnosticSet?, Index: Int): CXDiagnostic? val _Diags = Diags.rawValue val _Index = Index val res = externals.clang_getDiagnosticInSet(_Diags, _Index) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_loadDiagnostics(file: String?, error: CPointer?, errorString: CPointer?): CXDiagnosticSet? { @@ -520,7 +520,7 @@ fun clang_loadDiagnostics(file: String?, error: CPointer?, val _error = error.rawValue val _errorString = errorString.rawValue val res = externals.clang_loadDiagnostics(_file, _error, _errorString) - CPointer.createNullable(res) + interpretCPointer(res) } } @@ -533,7 +533,7 @@ fun clang_disposeDiagnosticSet(Diags: CXDiagnosticSet?): Unit { fun clang_getChildDiagnostics(D: CXDiagnostic?): CXDiagnosticSet? { val _D = D.rawValue val res = externals.clang_getChildDiagnostics(_D) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_getNumDiagnostics(Unit: CXTranslationUnit?): Int { @@ -546,13 +546,13 @@ fun clang_getDiagnostic(Unit: CXTranslationUnit?, Index: Int): CXDiagnostic? { val _Unit = Unit.rawValue val _Index = Index val res = externals.clang_getDiagnostic(_Unit, _Index) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_getDiagnosticSetFromTU(Unit: CXTranslationUnit?): CXDiagnosticSet? { val _Unit = Unit.rawValue val res = externals.clang_getDiagnosticSetFromTU(_Unit) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_disposeDiagnostic(Diagnostic: CXDiagnostic?): Unit { @@ -667,7 +667,7 @@ fun clang_createTranslationUnitFromSourceFile(CIdx: CXIndex?, source_filename: S val _num_unsaved_files = num_unsaved_files val _unsaved_files = unsaved_files.rawValue val res = externals.clang_createTranslationUnitFromSourceFile(_CIdx, _source_filename, _num_clang_command_line_args, _clang_command_line_args, _num_unsaved_files, _unsaved_files) - CPointer.createNullable(res) + interpretCPointer(res) } } @@ -676,7 +676,7 @@ fun clang_createTranslationUnit(CIdx: CXIndex?, ast_filename: String?): CXTransl val _CIdx = CIdx.rawValue val _ast_filename = ast_filename?.toCString(memScope).rawPtr val res = externals.clang_createTranslationUnit(_CIdx, _ast_filename) - CPointer.createNullable(res) + interpretCPointer(res) } } @@ -705,7 +705,7 @@ fun clang_parseTranslationUnit(CIdx: CXIndex?, source_filename: String?, command val _num_unsaved_files = num_unsaved_files val _options = options val res = externals.clang_parseTranslationUnit(_CIdx, _source_filename, _command_line_args, _num_command_line_args, _unsaved_files, _num_unsaved_files, _options) - CPointer.createNullable(res) + interpretCPointer(res) } } @@ -779,7 +779,7 @@ fun clang_reparseTranslationUnit(TU: CXTranslationUnit?, num_unsaved_files: Int, fun clang_getTUResourceUsageName(kind: CXTUResourceUsageKind): CPointer? { val _kind = kind.value val res = externals.clang_getTUResourceUsageName(_kind) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_getCXTUResourceUsage(TU: CXTranslationUnit?, retValPlacement: NativePlacement): CXTUResourceUsage { @@ -938,12 +938,12 @@ fun clang_getCursorLanguage(cursor: CXCursor): CXLanguageKind { fun clang_Cursor_getTranslationUnit(arg0: CXCursor): CXTranslationUnit? { val _arg0 = arg0.rawPtr val res = externals.clang_Cursor_getTranslationUnit(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_createCXCursorSet(): CXCursorSet? { val res = externals.clang_createCXCursorSet() - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_disposeCXCursorSet(cset: CXCursorSet?): Unit { @@ -997,7 +997,7 @@ fun clang_disposeOverriddenCursors(overridden: CPointer?): Unit { fun clang_getIncludedFile(cursor: CXCursor): CXFile? { val _cursor = cursor.rawPtr val res = externals.clang_getIncludedFile(_cursor) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_getCursor(arg0: CXTranslationUnit?, arg1: CXSourceLocation, retValPlacement: NativePlacement): CXCursor { @@ -1585,32 +1585,32 @@ fun clang_Cursor_getMangling(arg0: CXCursor, retValPlacement: NativePlacement): fun clang_Cursor_getCXXManglings(arg0: CXCursor): CPointer? { val _arg0 = arg0.rawPtr val res = externals.clang_Cursor_getCXXManglings(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_Cursor_getModule(C: CXCursor): CXModule? { val _C = C.rawPtr val res = externals.clang_Cursor_getModule(_C) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_getModuleForFile(arg0: CXTranslationUnit?, arg1: CXFile?): CXModule? { val _arg0 = arg0.rawValue val _arg1 = arg1.rawValue val res = externals.clang_getModuleForFile(_arg0, _arg1) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_Module_getASTFile(Module: CXModule?): CXFile? { val _Module = Module.rawValue val res = externals.clang_Module_getASTFile(_Module) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_Module_getParent(Module: CXModule?): CXModule? { val _Module = Module.rawValue val res = externals.clang_Module_getParent(_Module) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_Module_getName(Module: CXModule?, retValPlacement: NativePlacement): CXString { @@ -1645,7 +1645,7 @@ fun clang_Module_getTopLevelHeader(arg0: CXTranslationUnit?, Module: CXModule?, val _Module = Module.rawValue val _Index = Index val res = externals.clang_Module_getTopLevelHeader(_arg0, _Module, _Index) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_CXXConstructor_isConvertingConstructor(C: CXCursor): Int { @@ -1837,7 +1837,7 @@ fun clang_getCompletionChunkCompletionString(completion_string: CXCompletionStri val _completion_string = completion_string.rawValue val _chunk_number = chunk_number val res = externals.clang_getCompletionChunkCompletionString(_completion_string, _chunk_number) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_getNumCompletionChunks(completion_string: CXCompletionString?): Int { @@ -1890,7 +1890,7 @@ fun clang_getCompletionBriefComment(completion_string: CXCompletionString?, retV fun clang_getCursorCompletionString(cursor: CXCursor): CXCompletionString? { val _cursor = cursor.rawPtr val res = externals.clang_getCursorCompletionString(_cursor) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_defaultCodeCompleteOptions(): Int { @@ -1908,7 +1908,7 @@ fun clang_codeCompleteAt(TU: CXTranslationUnit?, complete_filename: String?, com val _num_unsaved_files = num_unsaved_files val _options = options val res = externals.clang_codeCompleteAt(_TU, _complete_filename, _complete_line, _complete_column, _unsaved_files, _num_unsaved_files, _options) - CPointer.createNullable(res) + interpretCPointer(res) } } @@ -1935,7 +1935,7 @@ fun clang_codeCompleteGetDiagnostic(Results: CPointer?, I val _Results = Results.rawValue val _Index = Index val res = externals.clang_codeCompleteGetDiagnostic(_Results, _Index) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_codeCompleteGetContexts(Results: CPointer?): Long { @@ -1988,7 +1988,7 @@ fun clang_getInclusions(tu: CXTranslationUnit?, visitor: CXInclusionVisitor?, cl fun clang_Cursor_Evaluate(C: CXCursor): CXEvalResult? { val _C = C.rawPtr val res = externals.clang_Cursor_Evaluate(_C) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_EvalResult_getKind(E: CXEvalResult?): CXEvalResultKind { @@ -2012,7 +2012,7 @@ fun clang_EvalResult_getAsDouble(E: CXEvalResult?): Double { fun clang_EvalResult_getAsStr(E: CXEvalResult?): CPointer? { val _E = E.rawValue val res = externals.clang_EvalResult_getAsStr(_E) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_EvalResult_dispose(E: CXEvalResult?): Unit { @@ -2025,7 +2025,7 @@ fun clang_getRemappings(path: String?): CXRemapping? { return memScoped { val _path = path?.toCString(memScope).rawPtr val res = externals.clang_getRemappings(_path) - CPointer.createNullable(res) + interpretCPointer(res) } } @@ -2033,7 +2033,7 @@ fun clang_getRemappingsFromFileList(filePaths: CPointer>?, val _filePaths = filePaths.rawValue val _numFiles = numFiles val res = externals.clang_getRemappingsFromFileList(_filePaths, _numFiles) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_remap_getNumFiles(arg0: CXRemapping?): Int { @@ -2082,49 +2082,49 @@ fun clang_index_isEntityObjCContainerKind(arg0: CXIdxEntityKind): Int { fun clang_index_getObjCContainerDeclInfo(arg0: CPointer?): CPointer? { val _arg0 = arg0.rawValue val res = externals.clang_index_getObjCContainerDeclInfo(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_index_getObjCInterfaceDeclInfo(arg0: CPointer?): CPointer? { val _arg0 = arg0.rawValue val res = externals.clang_index_getObjCInterfaceDeclInfo(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_index_getObjCCategoryDeclInfo(arg0: CPointer?): CPointer? { val _arg0 = arg0.rawValue val res = externals.clang_index_getObjCCategoryDeclInfo(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_index_getObjCProtocolRefListInfo(arg0: CPointer?): CPointer? { val _arg0 = arg0.rawValue val res = externals.clang_index_getObjCProtocolRefListInfo(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_index_getObjCPropertyDeclInfo(arg0: CPointer?): CPointer? { val _arg0 = arg0.rawValue val res = externals.clang_index_getObjCPropertyDeclInfo(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_index_getIBOutletCollectionAttrInfo(arg0: CPointer?): CPointer? { val _arg0 = arg0.rawValue val res = externals.clang_index_getIBOutletCollectionAttrInfo(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_index_getCXXClassDeclInfo(arg0: CPointer?): CPointer? { val _arg0 = arg0.rawValue val res = externals.clang_index_getCXXClassDeclInfo(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_index_getClientContainer(arg0: CPointer?): CXIdxClientContainer? { val _arg0 = arg0.rawValue val res = externals.clang_index_getClientContainer(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_index_setClientContainer(arg0: CPointer?, arg1: CXIdxClientContainer?): Unit { @@ -2137,7 +2137,7 @@ fun clang_index_setClientContainer(arg0: CPointer?, arg1: CX fun clang_index_getClientEntity(arg0: CPointer?): CXIdxClientEntity? { val _arg0 = arg0.rawValue val res = externals.clang_index_getClientEntity(_arg0) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_index_setClientEntity(arg0: CPointer?, arg1: CXIdxClientEntity?): Unit { @@ -2150,7 +2150,7 @@ fun clang_index_setClientEntity(arg0: CPointer?, arg1: CXIdxCli fun clang_IndexAction_create(CIdx: CXIndex?): CXIndexAction? { val _CIdx = CIdx.rawValue val res = externals.clang_IndexAction_create(_CIdx) - return CPointer.createNullable(res) + return interpretCPointer(res) } fun clang_IndexAction_dispose(arg0: CXIndexAction?): Unit { diff --git a/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt b/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt index 402e9a7c732..dc30a152d97 100644 --- a/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt +++ b/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt @@ -15,7 +15,7 @@ data class StableObjPtr private constructor(val value: COpaquePointer) { */ fun create(any: Any) = fromValue(newGlobalRef(any)) - private fun fromValue(value: NativePtr) = fromValue(CPointer.create(value)) + private fun fromValue(value: NativePtr) = fromValue(interpretCPointer(value)!!) /** * Creates [StableObjPtr] from given raw value. @@ -219,7 +219,7 @@ private fun ffiCreateCif(returnType: ffi_type, paramTypes: List): ffi_ private fun ffiFunImpl0(ffiCif: Long, ret: Long, args: Long, userData: Any) { ffiFunImpl(interpretPointed(ffiCif), - CPointer.create(ret), + interpretCPointer(ret)!!, interpretPointed(args), userData as UserData) } diff --git a/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt b/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt index 46129773ea1..1b53267fad6 100644 --- a/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt +++ b/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt @@ -11,21 +11,30 @@ val nativeNullPtr: NativePtr = 0L inline fun typeOf() = T::class.companionObjectInstance as CVariable.Type /** - * Returns interpretation of entity with given pointer. + * Returns interpretation of entity with given pointer, or `null` if it is null. * * @param T must not be abstract */ -inline fun interpretPointed(ptr: NativePtr): T { - return ensuringNotNull(ptr) { +inline fun interpretNullablePointed(ptr: NativePtr): T? { + if (ptr == nativeNullPtr) { + return null + } else { val kClass = T::class val primaryConstructor = kClass.primaryConstructor if (primaryConstructor == null) { throw IllegalArgumentException("${kClass.simpleName} doesn't have a constructor") } - (primaryConstructor as (NativePtr) -> T)(ptr) + return (primaryConstructor as (NativePtr) -> T)(ptr) } } +fun interpretCPointer(rawValue: NativePtr) = + if (rawValue == nativeNullPtr) { + null + } else { + CPointer(rawValue) + } + inline fun > CAdaptedFunctionType.Companion.getInstanceOf(): T = T::class.objectInstance!! diff --git a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Types.kt b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Types.kt index 69d367014ad..096a226b107 100644 --- a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Types.kt +++ b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Types.kt @@ -12,40 +12,14 @@ interface NativePointed { // `null` value of `NativePointed?` is mapped to `nativeNullPtr`. val NativePointed?.rawPtr: NativePtr - get() = this?.rawPtr ?: nativeNullPtr + get() = if (this != null) this.rawPtr else nativeNullPtr /** - * Returns interpretation of entity with given pointer, or `null` if it is null. + * Returns interpretation of entity with given pointer. * * @param T must not be abstract */ -inline fun interpretNullablePointed(ptr: NativePtr): T? { - return ifNotNull(ptr) { - interpretPointed(it) - } -} - -/** - * Applies the function to the pointer if it is not null, otherwise returns `null`. - */ -inline fun ifNotNull(ptr: NativePtr, function: (NativePtr)->T): T? { - return if (ptr == nativeNullPtr) { - null - } else { - function(ptr) - } -} - -/** - * Applies the function to the pointer ensuring that it is not null. - */ -inline fun ensuringNotNull(ptr: NativePtr, function: (NativePtr)->T): T { - if (ptr == nativeNullPtr) { - throw IllegalArgumentException() - } else { - return function(ptr) - } -} +inline fun interpretPointed(ptr: NativePtr): T = interpretNullablePointed(ptr)!! /** * Changes the interpretation of the pointed data or code. @@ -60,16 +34,7 @@ interface CPointed : NativePointed /** * C pointer. */ -class CPointer private constructor(val rawValue: NativePtr) { - companion object { - fun create(rawValue: NativePtr) = ensuringNotNull(rawValue) { - CPointer(rawValue) - } - - fun createNullable(rawValue: NativePtr) = ifNotNull(rawValue) { - CPointer(it) - } - } +class CPointer internal constructor(val rawValue: NativePtr) { override fun equals(other: Any?): Boolean { if (this === other) { @@ -90,7 +55,7 @@ class CPointer private constructor(val rawValue: NativePtr) { * Returns the pointer to this data or code. */ val T.ptr: CPointer - get() = CPointer.create(this.rawPtr) + get() = interpretCPointer(this.rawPtr)!! /** * Returns the corresponding [CPointed]. @@ -104,7 +69,7 @@ inline val CPointer.pointed: T val CPointer<*>?.rawValue: NativePtr get() = this?.rawValue ?: nativeNullPtr -fun CPointer<*>.reinterpret(): CPointer = CPointer.create(this.rawValue) +fun CPointer<*>.reinterpret(): CPointer = interpretCPointer(this.rawValue)!! /** * The [CPointed] without any specified interpretation. @@ -251,7 +216,7 @@ typealias CPointerVar = CPointerVarWithValueMappedTo> * The value of this variable. */ inline var > CPointerVarWithValueMappedTo

.value: P? - get() = CPointer.createNullable(nativeMemUtils.getNativePtr(this)) as P? + get() = interpretCPointer(nativeMemUtils.getNativePtr(this)) as P? set(value) = nativeMemUtils.putNativePtr(this, value.rawValue) /** diff --git a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt index 9dc03cf9639..f417ff1d378 100644 --- a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt +++ b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt @@ -151,10 +151,10 @@ fun NativePlacement.allocPointerTo() = alloc>() /** * The zero-terminated string. */ -class CString private constructor(override val rawPtr: NativePtr) : CPointed { +class CString(override val rawPtr: NativePtr) : CPointed { companion object { - fun fromArray(array: CArray) = CString(array.rawPtr) + fun fromArray(array: CArray) = array.reinterpret() } fun length(): Int { diff --git a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeMem.kt b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeMem.kt index 488241774b9..bc2d7ddabbf 100644 --- a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeMem.kt +++ b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeMem.kt @@ -51,7 +51,7 @@ object nativeMemUtils { if (ptr == nativeNullPtr) { throw OutOfMemoryError("unable to allocate native memory") } - return NativeAllocated(ptr) + return interpretPointed(ptr) } fun free(mem: NativePointed) { diff --git a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeTypes.kt b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeTypes.kt index dc3a545ed57..f60e5b2b707 100644 --- a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeTypes.kt +++ b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeTypes.kt @@ -14,11 +14,17 @@ inline val nativeNullPtr: NativePtr fun typeOf(): CVariable.Type = throw Error("typeOf() is called with erased argument") /** - * Returns interpretation of entity with given pointer. + * Returns interpretation of entity with given pointer, or `null` if it is null. * * @param T must not be abstract */ -@Intrinsic external fun interpretPointed(ptr: NativePtr): T +@Intrinsic external fun interpretNullablePointed(ptr: NativePtr): T? + +@Intrinsic external fun interpretCPointer(rawValue: NativePtr): CPointer? + +@Intrinsic external fun NativePointed.getRawPointer(): NativePtr + +@Intrinsic external fun CPointer<*>.getRawValue(): NativePtr inline fun > CAdaptedFunctionType.Companion.getInstanceOf(): T = TODO("CAdaptedFunctionType.getInstanceOf") diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt index f9a16c20b07..2f41203ec48 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt @@ -276,7 +276,7 @@ class StubGenerator( class Pointer(val pointee: String) : TypeInfo() { override fun argToJni(name: String) = "$name.rawValue" - override fun argFromJni(name: String) = "CPointer.createNullable<$pointee>($name)" + override fun argFromJni(name: String) = "interpretCPointer<$pointee>($name)" override val jniType: String get() = "NativePtr" diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt index 1466e6bed27..a93fa71890e 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt @@ -6,6 +6,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.types.TypeUtils private val cPointerName = "CPointer" private val nativePointedName = "NativePointed" @@ -37,12 +38,26 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns) { val cPointerRawValue = cPointer.unsubstitutedMemberScope.getContributedVariables("rawValue").single() + val cPointerGetRawValue = packageScope.getContributedFunctions("getRawValue").single { + val extensionReceiverParameter = it.extensionReceiverParameter + extensionReceiverParameter != null && + TypeUtils.getClassDescriptor(extensionReceiverParameter.type) == cPointer + } + val nativePointedRawPtrGetter = nativePointed.unsubstitutedMemberScope.getContributedVariables("rawPtr").single().getter!! + val nativePointedGetRawPointer = packageScope.getContributedFunctions("getRawPointer").single { + val extensionReceiverParameter = it.extensionReceiverParameter + extensionReceiverParameter != null && + TypeUtils.getClassDescriptor(extensionReceiverParameter.type) == nativePointed + } + val memberAt = packageScope.getContributedFunctions("memberAt").single() - val interpretPointed = packageScope.getContributedFunctions("interpretPointed").single() + val interpretNullablePointed = packageScope.getContributedFunctions("interpretNullablePointed").single() + + val interpretCPointer = packageScope.getContributedFunctions("interpretCPointer").single() val arrayGetByIntIndex = packageScope.getContributedFunctions("get").single { KotlinBuiltIns.isInt(it.valueParameters.single().type) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index e08511f3179..77cc70ad2d8 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -48,6 +48,9 @@ internal class KonanLower(val context: Context) { phaser.phase(KonanPhase.LOWER_INNER_CLASSES) { InnerClassLowering(context).runOnFilePostfix(irFile) } + phaser.phase(KonanPhase.LOWER_INTEROP) { + InteropLowering(context).lower(irFile) + } phaser.phase(KonanPhase.LOWER_CALLABLES) { CallableReferenceLowering(context).runOnFilePostfix(irFile) } @@ -62,8 +65,5 @@ internal class KonanLower(val context: Context) { phaser.phase(KonanPhase.AUTOBOX) { Autoboxing(context).lower(irFile) } - phaser.phase(KonanPhase.LOWER_INTEROP) { - InteropLowering(context).lower(irFile) - } } } 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 d29d8c83971..cdb5f2f7625 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 @@ -1661,6 +1661,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val interop = context.interopBuiltIns return when (descriptor) { + interop.interpretNullablePointed, interop.interpretCPointer, + interop.nativePointedGetRawPointer, interop.cPointerGetRawValue -> args.single() + in interop.readPrimitive -> { val pointerType = pointerType(codegen.getLLVMType(descriptor.returnType!!)) val rawPointer = args.last() diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt index fc65acd814c..4354a018e83 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt @@ -148,20 +148,25 @@ private class InteropTransformer(val context: Context) : IrBuildingTransformer(c if (descriptor is ClassConstructorDescriptor) { val type = descriptor.constructedClass.defaultType if (type.isRepresentedAs(ValueType.C_POINTER) || type.isRepresentedAs(ValueType.NATIVE_POINTED)) { - return expression.getValueArgument(0)!! + throw Error("Native interop types constructors must not be called directly") } } if (descriptor == interop.nativePointedRawPtrGetter || OverridingUtil.overrides(descriptor, interop.nativePointedRawPtrGetter)) { - return expression.dispatchReceiver!! + // Replace by the intrinsic call to be handled by code generator: + return builder.irCall(interop.nativePointedGetRawPointer).apply { + extensionReceiver = expression.dispatchReceiver + } } return when (descriptor) { - interop.cPointerRawValue.getter -> expression.dispatchReceiver!! - - interop.interpretPointed -> expression.getValueArgument(0)!! + interop.cPointerRawValue.getter -> + // Replace by the intrinsic call to be handled by code generator: + builder.irCall(interop.cPointerGetRawValue).apply { + extensionReceiver = expression.dispatchReceiver + } interop.arrayGetByIntIndex, interop.arrayGetByLongIndex -> { val array = expression.extensionReceiver!!