Merge branch 'master' into inline

This commit is contained in:
KonstantinAnisimov
2017-02-06 17:21:28 +07:00
committed by GitHub
51 changed files with 1155 additions and 243 deletions
@@ -150,9 +150,6 @@ abstract class CAdaptedFunctionTypeImpl<F : Function<*>>
private typealias UserData = (ret: COpaquePointer, args: CArray<COpaquePointerVar>)->Unit private typealias UserData = (ret: COpaquePointer, args: CArray<COpaquePointerVar>)->Unit
inline fun <reified T : CAdaptedFunctionTypeImpl<*>> CAdaptedFunctionTypeImpl.Companion.of(): T =
T::class.objectInstance!!
private fun loadCallbacksLibrary() { private fun loadCallbacksLibrary() {
System.loadLibrary("callbacks") System.loadLibrary("callbacks")
} }
@@ -38,12 +38,12 @@ object nativeMemUtils {
fun getDouble(mem: NativePointed) = unsafe.getDouble(mem.address) fun getDouble(mem: NativePointed) = unsafe.getDouble(mem.address)
fun putDouble(mem: NativePointed, value: Double) = unsafe.putDouble(mem.address, value) fun putDouble(mem: NativePointed, value: Double) = unsafe.putDouble(mem.address, value)
fun getPtr(mem: NativePointed): NativePtr = when (dataModel) { fun getNativePtr(mem: NativePointed): NativePtr = when (dataModel) {
DataModel._32BIT -> getInt(mem).toLong() DataModel._32BIT -> getInt(mem).toLong()
DataModel._64BIT -> getLong(mem) DataModel._64BIT -> getLong(mem)
} }
fun putPtr(mem: NativePointed, value: NativePtr) = when (dataModel) { fun putNativePtr(mem: NativePointed, value: NativePtr) = when (dataModel) {
DataModel._32BIT -> putInt(mem, value.toInt()) DataModel._32BIT -> putInt(mem, value.toInt())
DataModel._64BIT -> putLong(mem, value) DataModel._64BIT -> putLong(mem, value)
} }
@@ -8,7 +8,7 @@ val nativeNullPtr: NativePtr = 0L
// TODO: the functions below should eventually be intrinsified // TODO: the functions below should eventually be intrinsified
inline fun <reified T : CVariable> CVariable.Type.Companion.of() = T::class.companionObjectInstance as CVariable.Type inline fun <reified T : CVariable> typeOf() = T::class.companionObjectInstance as CVariable.Type
/** /**
* Returns interpretation of entity with given pointer. * Returns interpretation of entity with given pointer.
@@ -28,3 +28,5 @@ inline fun <reified T : NativePointed> interpretPointed(ptr: NativePtr): T {
inline fun <reified T : CAdaptedFunctionType<*>> CAdaptedFunctionType.Companion.getInstanceOf(): T = inline fun <reified T : CAdaptedFunctionType<*>> CAdaptedFunctionType.Companion.getInstanceOf(): T =
T::class.objectInstance!! T::class.objectInstance!!
internal fun CPointer<*>.cPointerToString() = "CPointer(raw=0x%x)".format(rawValue)
@@ -0,0 +1,4 @@
package kotlinx.cinterop
internal fun decodeFromUtf8(bytes: ByteArray) = String(bytes)
internal fun encodeToUtf8(str: String) = str.toByteArray()
@@ -83,9 +83,7 @@ class CPointer<T : CPointed> private constructor(val rawValue: NativePtr) {
return rawValue.hashCode() return rawValue.hashCode()
} }
override fun toString(): String { override fun toString() = this.cPointerToString()
return "CPointer(raw=0x%x)".format(rawValue)
}
} }
/** /**
@@ -141,18 +139,15 @@ interface CVariable : CPointed {
open class Type(val size: Long, val align: Int) { open class Type(val size: Long, val align: Int) {
init { init {
assert (size % align == 0L) require(size % align == 0L)
} }
companion object
}
companion object {
inline fun <reified T : CVariable> sizeOf() = Type.of<T>().size
inline fun <reified T : CVariable> alignOf() = Type.of<T>().align
} }
} }
inline fun <reified T : CVariable> sizeOf() = typeOf<T>().size
inline fun <reified T : CVariable> alignOf() = typeOf<T>().align
/** /**
* The C data which is composed from several members. * The C data which is composed from several members.
*/ */
@@ -177,7 +172,7 @@ abstract class CStructVar : CVariable, CAggregate {
*/ */
sealed class CPrimitiveVar : CVariable { sealed class CPrimitiveVar : CVariable {
// aligning by size is obviously enough // aligning by size is obviously enough
open class Type(size: Int, align: Int = size) : CVariable.Type(size.toLong(), align) open class Type(size: Int) : CVariable.Type(size.toLong(), align = size)
} }
abstract class CEnumVar : CPrimitiveVar() abstract class CEnumVar : CPrimitiveVar()
@@ -256,8 +251,8 @@ typealias CPointerVar<T> = CPointerVarWithValueMappedTo<CPointer<T>>
* The value of this variable. * The value of this variable.
*/ */
inline var <reified P : CPointer<*>> CPointerVarWithValueMappedTo<P>.value: P? inline var <reified P : CPointer<*>> CPointerVarWithValueMappedTo<P>.value: P?
get() = CPointer.createNullable<CPointed>(nativeMemUtils.getPtr(this)) as P? get() = CPointer.createNullable<CPointed>(nativeMemUtils.getNativePtr(this)) as P?
set(value) = nativeMemUtils.putPtr(this, value.rawValue) set(value) = nativeMemUtils.putNativePtr(this, value.rawValue)
/** /**
* The code or data pointed by the value of this variable. * The code or data pointed by the value of this variable.
@@ -275,7 +270,7 @@ class CArray<T : CVariable>(override val rawPtr: NativePtr) : CAggregate
inline fun <reified T : CVariable> CArray<T>.elementOffset(index: Long) = if (index == 0L) { inline fun <reified T : CVariable> CArray<T>.elementOffset(index: Long) = if (index == 0L) {
0L // optimization for JVM impl which uses reflection for now. 0L // optimization for JVM impl which uses reflection for now.
} else { } else {
index * CVariable.sizeOf<T>() index * sizeOf<T>()
} }
inline operator fun <reified T : CVariable> CArray<T>.get(index: Long): T = memberAt(elementOffset(index)) inline operator fun <reified T : CVariable> CArray<T>.get(index: Long): T = memberAt(elementOffset(index))
@@ -20,22 +20,22 @@ object nativeHeap : NativeFreeablePlacement {
// TODO: implement optimally // TODO: implement optimally
class Arena(private val parent: NativeFreeablePlacement = nativeHeap) : NativePlacement { class Arena(private val parent: NativeFreeablePlacement = nativeHeap) : NativePlacement {
private val allocatedChunks = mutableListOf<NativePointed>() private val allocatedChunks = ArrayList<NativePointed>()
override fun alloc(size: Long, align: Int): NativePointed { override fun alloc(size: Long, align: Int): NativePointed {
val res = nativeHeap.alloc(size, align) val res = parent.alloc(size, align)
try { try {
allocatedChunks.add(res) allocatedChunks.add(res)
return res return res
} catch (e: Throwable) { } catch (e: Throwable) {
nativeHeap.free(res) parent.free(res)
throw e throw e
} }
} }
fun clear() { fun clear() {
allocatedChunks.forEach { allocatedChunks.forEach {
nativeHeap.free(it) parent.free(it)
} }
allocatedChunks.clear() allocatedChunks.clear()
@@ -51,7 +51,7 @@ fun NativePlacement.alloc(size: Int, align: Int) = alloc(size.toLong(), align)
* @param T must not be abstract * @param T must not be abstract
*/ */
inline fun <reified T : CVariable> NativePlacement.alloc(): T = inline fun <reified T : CVariable> NativePlacement.alloc(): T =
alloc(CVariable.sizeOf<T>(), CVariable.alignOf<T>()).reinterpret() alloc(sizeOf<T>(), alignOf<T>()).reinterpret()
/** /**
* Allocates C array of given elements type and length. * Allocates C array of given elements type and length.
@@ -59,7 +59,7 @@ inline fun <reified T : CVariable> NativePlacement.alloc(): T =
* @param T must not be abstract * @param T must not be abstract
*/ */
inline fun <reified T : CVariable> NativePlacement.allocArray(length: Long): CArray<T> = inline fun <reified T : CVariable> NativePlacement.allocArray(length: Long): CArray<T> =
alloc(CVariable.sizeOf<T>() * length, CVariable.alignOf<T>()).reinterpret() alloc(sizeOf<T>() * length, alignOf<T>()).reinterpret()
/** /**
* Allocates C array of given elements type and length. * Allocates C array of given elements type and length.
@@ -78,7 +78,7 @@ inline fun <reified T : CVariable> NativePlacement.allocArray(length: Long,
initializer: T.(index: Long)->Unit): CArray<T> { initializer: T.(index: Long)->Unit): CArray<T> {
val res = allocArray<T>(length) val res = allocArray<T>(length)
(0 until length).forEach { index -> (0 .. length - 1).forEach { index ->
res[index].initializer(index) res[index].initializer(index)
} }
@@ -112,7 +112,7 @@ fun <T : CPointed> NativePlacement.allocArrayOfPointersTo(elements: List<T?>): C
* Allocates C array of pointers to given elements. * Allocates C array of pointers to given elements.
*/ */
fun <T : CPointed> NativePlacement.allocArrayOfPointersTo(vararg elements: T?) = fun <T : CPointed> NativePlacement.allocArrayOfPointersTo(vararg elements: T?) =
allocArrayOfPointersTo(elements.toList()) allocArrayOfPointersTo(listOf(*elements))
/** /**
* Allocates C array of given values. * Allocates C array of given values.
@@ -120,7 +120,7 @@ fun <T : CPointed> NativePlacement.allocArrayOfPointersTo(vararg elements: T?) =
inline fun <reified T : CPointer<*>> inline fun <reified T : CPointer<*>>
NativePlacement.allocArrayOf(vararg elements: T?): CArray<CPointerVarWithValueMappedTo<T>> { NativePlacement.allocArrayOf(vararg elements: T?): CArray<CPointerVarWithValueMappedTo<T>> {
return allocArrayOf(elements.toList()) return allocArrayOf(listOf(*elements))
} }
/** /**
@@ -139,8 +139,9 @@ inline fun <reified T : CPointer<*>>
fun NativePlacement.allocArrayOf(elements: ByteArray): CArray<CInt8Var> { fun NativePlacement.allocArrayOf(elements: ByteArray): CArray<CInt8Var> {
val res = allocArray<CInt8Var>(elements.size) val res = allocArray<CInt8Var>(elements.size)
elements.forEachIndexed { i, byte -> var index = 0
res[i].value = byte for (byte in elements) {
res[index++].value = byte
} }
return res return res
} }
@@ -173,7 +174,7 @@ class CString private constructor(override val rawPtr: NativePtr) : CPointed {
val bytes = ByteArray(len) val bytes = ByteArray(len)
nativeMemUtils.getByteArray(array[0], bytes, len) nativeMemUtils.getByteArray(array[0], bytes, len)
return String(bytes) // TODO: encoding return decodeFromUtf8(bytes) // TODO: encoding
} }
fun asCharPtr() = reinterpret<CInt8Var>() fun asCharPtr() = reinterpret<CInt8Var>()
@@ -184,9 +185,9 @@ fun CString.Companion.fromString(str: String?, placement: NativePlacement): CStr
return null return null
} }
val bytes = str.toByteArray() // TODO: encoding val bytes = encodeToUtf8(str) // TODO: encoding
val len = bytes.size val len = bytes.size
val nativeBytes = nativeHeap.allocArray<CInt8Var>(len + 1) val nativeBytes = placement.allocArray<CInt8Var>(len + 1)
nativeMemUtils.putByteArray(bytes, nativeBytes[0], len) nativeMemUtils.putByteArray(bytes, nativeBytes[0], len)
nativeBytes[len].value = 0 nativeBytes[len].value = 0
@@ -197,20 +198,16 @@ fun CString.Companion.fromString(str: String?, placement: NativePlacement): CStr
fun CPointer<CInt8Var>.asCString() = CString.fromArray(this.reinterpret<CArray<CInt8Var>>().pointed) fun CPointer<CInt8Var>.asCString() = CString.fromArray(this.reinterpret<CArray<CInt8Var>>().pointed)
fun String.toCString(placement: NativePlacement) = CString.fromString(this, placement) fun String.toCString(placement: NativePlacement) = CString.fromString(this, placement)
class MemScope private constructor(private val arena: Arena) : NativePlacement by arena { class MemScope : NativePlacement {
private val arena = Arena()
override fun alloc(size: Long, align: Int) = arena.alloc(size, align)
fun clear() = arena.clear()
val memScope: NativePlacement val memScope: NativePlacement
get() = this get() = this
companion object {
internal inline fun <R> use(block: MemScope.()->R): R {
val memScope = MemScope(Arena())
try {
return memScope.block()
} finally {
memScope.arena.clear()
}
}
}
} }
/** /**
@@ -218,6 +215,10 @@ class MemScope private constructor(private val arena: Arena) : NativePlacement b
* which will be automatically disposed at the end of this scope. * which will be automatically disposed at the end of this scope.
*/ */
inline fun <R> memScoped(block: MemScope.()->R): R { inline fun <R> memScoped(block: MemScope.()->R): R {
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") // TODO: it is a hack val memScope = MemScope()
return MemScope.use(block) try {
return memScope.block()
} finally {
memScope.clear()
}
} }
@@ -0,0 +1,66 @@
package kotlinx.cinterop
import konan.internal.Intrinsic
internal inline val pointerSize: Int
get() = getPointerSize()
@Intrinsic external fun getPointerSize(): Int
// TODO: do not use singleton because it leads to init-check on any access.
object nativeMemUtils {
@Intrinsic external fun getByte(mem: NativePointed): Byte
@Intrinsic external fun putByte(mem: NativePointed, value: Byte)
@Intrinsic external fun getShort(mem: NativePointed): Short
@Intrinsic external fun putShort(mem: NativePointed, value: Short)
@Intrinsic external fun getInt(mem: NativePointed): Int
@Intrinsic external fun putInt(mem: NativePointed, value: Int)
@Intrinsic external fun getLong(mem: NativePointed): Long
@Intrinsic external fun putLong(mem: NativePointed, value: Long)
@Intrinsic external fun getFloat(mem: NativePointed): Float
@Intrinsic external fun putFloat(mem: NativePointed, value: Float)
@Intrinsic external fun getDouble(mem: NativePointed): Double
@Intrinsic external fun putDouble(mem: NativePointed, value: Double)
@Intrinsic external fun getNativePtr(mem: NativePointed): NativePtr
@Intrinsic external fun putNativePtr(mem: NativePointed, value: NativePtr)
fun getByteArray(source: NativePointed, dest: ByteArray, length: Int) {
val sourceArray: CArray<CInt8Var> = source.reinterpret()
for (index in 0 .. length - 1) {
dest[index] = sourceArray[index].value
}
}
fun putByteArray(source: ByteArray, dest: NativePointed, length: Int) {
val destArray: CArray<CInt8Var> = dest.reinterpret()
for (index in 0 .. length - 1) {
destArray[index].value = source[index]
}
}
private class NativeAllocated(override val rawPtr: NativePtr) : NativePointed
fun alloc(size: Long, align: Int): NativePointed {
val ptr = malloc(size, align)
if (ptr == nativeNullPtr) {
throw OutOfMemoryError("unable to allocate native memory")
}
return NativeAllocated(ptr)
}
fun free(mem: NativePointed) {
free(mem.rawPtr)
}
}
@SymbolName("Kotlin_interop_malloc")
private external fun malloc(size: Long, align: Int): NativePtr
@SymbolName("Kotlin_interop_free")
private external fun free(ptr: NativePtr)
@@ -0,0 +1,26 @@
package kotlinx.cinterop
import konan.internal.Intrinsic
class NativePtr private constructor() {
@Intrinsic external operator fun plus(offset: Long): NativePtr
}
inline val nativeNullPtr: NativePtr
get() = getNativeNullPtr()
@Intrinsic external fun getNativeNullPtr(): NativePtr
fun <T : CVariable> typeOf(): CVariable.Type = throw Error("typeOf() is called with erased argument")
/**
* Returns interpretation of entity with given pointer.
*
* @param T must not be abstract
*/
@Intrinsic external fun <T : NativePointed> interpretPointed(ptr: NativePtr): T
inline fun <reified T : CAdaptedFunctionType<*>> CAdaptedFunctionType.Companion.getInstanceOf(): T =
TODO("CAdaptedFunctionType.getInstanceOf")
internal fun CPointer<*>.cPointerToString() = "CPointer(raw=$rawValue)"
@@ -0,0 +1,16 @@
package kotlinx.cinterop
internal fun decodeFromUtf8(bytes: ByteArray): String = kotlin.text.fromUtf8Array(bytes, 0, bytes.size)
fun encodeToUtf8(str: String): ByteArray {
val result = ByteArray(str.length)
for (index in 0 .. str.length - 1) {
val char = str[index]
if (char.toInt() >= 128) {
TODO("non-ASCII char")
}
result[index] = char.toByte()
}
return result
}
@@ -3,12 +3,20 @@ package org.jetbrains.kotlin.native.interop.gen.jvm
import org.jetbrains.kotlin.native.interop.indexer.* import org.jetbrains.kotlin.native.interop.indexer.*
import java.lang.IllegalStateException import java.lang.IllegalStateException
enum class KotlinPlatform {
JVM,
NATIVE
}
// TODO: mostly rename 'jni' to 'c'.
class StubGenerator( class StubGenerator(
val nativeIndex: NativeIndex, val nativeIndex: NativeIndex,
val pkgName: String, val pkgName: String,
val libName: String, val libName: String,
val excludedFunctions: Set<String>, val excludedFunctions: Set<String>,
val dumpShims: Boolean) { val dumpShims: Boolean,
val platform: KotlinPlatform = KotlinPlatform.JVM) {
/** /**
* The names that should not be used for struct classes to prevent name clashes * The names that should not be used for struct classes to prevent name clashes
@@ -253,7 +261,7 @@ class StubGenerator(
override fun argFromJni(name: String) = "CPointer.createNullable<$pointee>($name)" override fun argFromJni(name: String) = "CPointer.createNullable<$pointee>($name)"
override val jniType: String override val jniType: String
get() = "Long" get() = "NativePtr"
override fun constructPointedType(valueType: String) = "CPointerVarWithValueMappedTo<$valueType>" override fun constructPointedType(valueType: String) = "CPointerVarWithValueMappedTo<$valueType>"
} }
@@ -264,7 +272,7 @@ class StubGenerator(
override fun argFromJni(name: String) = "interpretPointed<$pointed>($name)" override fun argFromJni(name: String) = "interpretPointed<$pointed>($name)"
override val jniType: String override val jniType: String
get() = "Long" get() = "NativePtr"
override fun constructPointedType(valueType: String): String { override fun constructPointedType(valueType: String): String {
// TODO: this method must not exist // TODO: this method must not exist
@@ -390,7 +398,7 @@ class StubGenerator(
kotlinType = "String?", kotlinType = "String?",
kotlinConv = { name -> "$name?.toCString(memScope).rawPtr" }, kotlinConv = { name -> "$name?.toCString(memScope).rawPtr" },
memScoped = true, memScoped = true,
kotlinJniBridgeType = "Long" kotlinJniBridgeType = "NativePtr"
) )
} }
} }
@@ -573,7 +581,7 @@ class StubGenerator(
paramBindings.add(OutValueBinding( paramBindings.add(OutValueBinding(
kotlinType = "NativePlacement", kotlinType = "NativePlacement",
kotlinConv = { name -> "$name.alloc<${retValMirror.pointedTypeName}>().rawPtr" }, kotlinConv = { name -> "$name.alloc<${retValMirror.pointedTypeName}>().rawPtr" },
kotlinJniBridgeType = "Long" kotlinJniBridgeType = "NativePtr"
)) ))
} }
@@ -614,7 +622,7 @@ class StubGenerator(
val header = "fun ${func.name}($args): ${retValBinding.kotlinType}" val header = "fun ${func.name}($args): ${retValBinding.kotlinType}"
fun generateBody() { fun generateBody(memScoped: Boolean) {
val externalParamNames = paramNames.mapIndexed { i: Int, name: String -> val externalParamNames = paramNames.mapIndexed { i: Int, name: String ->
val binding = paramBindings[i] val binding = paramBindings[i]
val externalParamName: String val externalParamName: String
@@ -631,8 +639,9 @@ class StubGenerator(
} }
out("val res = externals.${func.name}(" + externalParamNames.joinToString(", ") + ")") out("val res = externals.${func.name}(" + externalParamNames.joinToString(", ") + ")")
val result = retValBinding.conv("res")
if (dumpShims) { if (dumpShims) {
val returnValueRepresentation = retValBinding.conv("res") val returnValueRepresentation = result
out("print(\"\${${returnValueRepresentation}}\\t= \")") out("print(\"\${${returnValueRepresentation}}\\t= \")")
out("print(\"${func.name}( \")") out("print(\"${func.name}( \")")
val argsRepresentation = paramNames.map{"\${${it}}"}.joinToString(", ") val argsRepresentation = paramNames.map{"\${${it}}"}.joinToString(", ")
@@ -640,17 +649,21 @@ class StubGenerator(
out("println(\")\")") out("println(\")\")")
} }
out("return " + retValBinding.conv("res")) if (memScoped) {
out(result)
} else {
out("return " + result)
}
} }
block(header) { block(header) {
val memScoped = paramBindings.any { it.memScoped } val memScoped = paramBindings.any { it.memScoped }
if (memScoped) { if (memScoped) {
block("memScoped") { block("return memScoped") {
generateBody() generateBody(true)
} }
} else { } else {
generateBody() generateBody(false)
} }
} }
} }
@@ -696,6 +709,11 @@ class StubGenerator(
private fun generateFunctionType(type: FunctionType, name: String) { private fun generateFunctionType(type: FunctionType, name: String) {
val kotlinFunctionType = getKotlinFunctionType(type) val kotlinFunctionType = getKotlinFunctionType(type)
if (platform == KotlinPlatform.NATIVE) {
out("object $name : CFunctionType {}")
return
}
val constructorArgs = listOf(getRetValFfiType(type.returnType)) + val constructorArgs = listOf(getRetValFfiType(type.returnType)) +
type.parameterTypes.map { getArgFfiType(it) } type.parameterTypes.map { getArgFfiType(it) }
@@ -727,6 +745,12 @@ class StubGenerator(
} }
} }
private val FunctionDecl.stubSymbolName: String
get() {
require(platform == KotlinPlatform.NATIVE)
return "kni_" + pkgName.replace('/', '_') + '_' + this.name
}
/** /**
* Produces to [out] the definition of Kotlin JNI function used in binding for given C function. * Produces to [out] the definition of Kotlin JNI function used in binding for given C function.
*/ */
@@ -739,6 +763,9 @@ class StubGenerator(
"$name: " + paramBindings[i].kotlinJniBridgeType "$name: " + paramBindings[i].kotlinJniBridgeType
}.joinToString(", ") }.joinToString(", ")
if (platform == KotlinPlatform.NATIVE) {
out("@SymbolName(\"${func.stubSymbolName}\")")
}
out("external fun ${func.name}($args): ${retValBinding.kotlinJniBridgeType}") out("external fun ${func.name}($args): ${retValBinding.kotlinJniBridgeType}")
} }
@@ -797,7 +824,9 @@ class StubGenerator(
} }
block("object externals") { block("object externals") {
out("init { System.loadLibrary(\"$libName\") }") if (platform == KotlinPlatform.JVM) {
out("init { System.loadLibrary(\"$libName\") }")
}
functionsToBind.forEach { functionsToBind.forEach {
try { try {
transaction { transaction {
@@ -811,6 +840,28 @@ class StubGenerator(
} }
} }
/**
* Returns the C type to be used for value of given Kotlin type in JNI function implementation.
*/
fun getCBridgeType(kotlinJniBridgeType: String): String {
return when (platform) {
KotlinPlatform.JVM -> getCJniBridgeType(kotlinJniBridgeType)
KotlinPlatform.NATIVE -> getCNativeBridgeType(kotlinJniBridgeType)
}
}
fun getCNativeBridgeType(kotlinJniBridgeType: String) = when (kotlinJniBridgeType) {
"Unit" -> "void"
"Byte" -> "int8_t"
"Short" -> "int16_t"
"Int" -> "int32_t"
"Long" -> "int64_t"
"Float" -> "float"
"Double" -> "double" // TODO: float32_t, float64_t?
"NativePtr" -> "void*"
else -> TODO(kotlinJniBridgeType)
}
/** /**
* Returns the C type to be used for value of given Kotlin type in JNI function implementation. * Returns the C type to be used for value of given Kotlin type in JNI function implementation.
*/ */
@@ -819,7 +870,9 @@ class StubGenerator(
"Byte" -> "jbyte" "Byte" -> "jbyte"
"Short" -> "jshort" "Short" -> "jshort"
"Int" -> "jint" "Int" -> "jint"
"Long" -> "jlong" "Long", "NativePtr" -> "jlong"
"Float" -> "jfloat"
"Double" -> "jdouble"
else -> throw NotImplementedError(kotlinJniBridgeType) else -> throw NotImplementedError(kotlinJniBridgeType)
} }
@@ -828,7 +881,9 @@ class StubGenerator(
*/ */
fun generateCFile(headerFiles: List<String>) { fun generateCFile(headerFiles: List<String>) {
out("#include <stdint.h>") out("#include <stdint.h>")
out("#include <jni.h>") if (platform == KotlinPlatform.JVM) {
out("#include <jni.h>")
}
headerFiles.forEach { headerFiles.forEach {
out("#include <$it>") out("#include <$it>")
} }
@@ -856,11 +911,11 @@ class StubGenerator(
if (paramBindings.isEmpty()) if (paramBindings.isEmpty())
"" ""
else paramBindings else paramBindings
.map { getCJniBridgeType(it.kotlinJniBridgeType) } .map { getCBridgeType(it.kotlinJniBridgeType) }
.mapIndexed { i, type -> "$type ${paramNames[i]}" } .mapIndexed { i, type -> "$type ${paramNames[i]}" }
.joinToString(separator = ", ", prefix = ", ") .joinToString(separator = ", ", prefix = ", ")
val cReturnType = getCJniBridgeType(retValBinding.kotlinJniBridgeType) val cReturnType = getCBridgeType(retValBinding.kotlinJniBridgeType)
val params = func.parameters.mapIndexed { i, parameter -> val params = func.parameters.mapIndexed { i, parameter ->
val cType = parameter.type.getStringRepresentation() val cType = parameter.type.getStringRepresentation()
@@ -872,14 +927,26 @@ class StubGenerator(
}.joinToString(", ") }.joinToString(", ")
val callExpr = "${func.name}($params)" val callExpr = "${func.name}($params)"
val funcFullName = if (pkgName.isEmpty()) { val jniFuncName = when (platform) {
"externals.${func.name}" KotlinPlatform.JVM -> {
} else { val funcFullName = if (pkgName.isEmpty()) {
"$pkgName.externals.${func.name}" "externals.${func.name}"
} else {
"$pkgName.externals.${func.name}"
}
"Java_" + funcFullName.replace("_", "_1").replace('.', '_').replace("$", "_00024")
}
KotlinPlatform.NATIVE -> {
func.stubSymbolName
}
} }
val jniFuncName = "Java_" + funcFullName.replace("_", "_1").replace('.', '_').replace("$", "_00024")
block("JNIEXPORT $cReturnType JNICALL $jniFuncName (JNIEnv *env, jobject obj$args)") { val funcDecl = when (platform) {
KotlinPlatform.JVM -> "JNIEXPORT $cReturnType JNICALL $jniFuncName (JNIEnv *env, jobject obj$args)"
KotlinPlatform.NATIVE -> "$cReturnType $jniFuncName (void* obj$args)"
}
block(funcDecl) {
if (cReturnType == "void") { if (cReturnType == "void") {
out("$callExpr;") out("$callExpr;")
@@ -99,6 +99,10 @@ private fun processLib(ktGenRoot: String,
val args = additionalArgs.groupBy ({ getArgPrefix(it)!! }, { dropPrefix(it)!! }) // TODO val args = additionalArgs.groupBy ({ getArgPrefix(it)!! }, { dropPrefix(it)!! }) // TODO
val platformName = args["-target"]?.single() ?: "jvm"
val platform = KotlinPlatform.values().single { it.name.equals(platformName, ignoreCase = true) }
val defFile = args["-def"]?.single()?.let { File(it) } val defFile = args["-def"]?.single()?.let { File(it) }
val config = Properties() val config = Properties()
@@ -133,7 +137,7 @@ private fun processLib(ktGenRoot: String,
val nativeIndex = buildNativeIndex(headerFiles, compilerOpts) val nativeIndex = buildNativeIndex(headerFiles, compilerOpts)
val gen = StubGenerator(nativeIndex, outKtPkg, libName, excludedFunctions, generateShims) val gen = StubGenerator(nativeIndex, outKtPkg, libName, excludedFunctions, generateShims, platform)
outKtFile.parentFile.mkdirs() outKtFile.parentFile.mkdirs()
outKtFile.bufferedWriter().use { out -> outKtFile.bufferedWriter().use { out ->
@@ -151,36 +155,50 @@ private fun processLib(ktGenRoot: String,
} }
} }
val outOFile = createTempFile(suffix = ".o") File(nativeLibsDir).mkdirs()
val javaHome = System.getProperty("java.home")
val compilerArgsForJniIncludes = listOf("", "linux", "darwin").map { "-I$javaHome/../include/$it" }.toTypedArray()
val compilerCmd = arrayOf("$llvmInstallPath/bin/$compiler", *compilerOpts.toTypedArray(),
*compilerArgsForJniIncludes,
"-c", outCFile.path, "-o", outOFile.path)
val workDir = defFile?.parentFile ?: File(System.getProperty("java.io.tmpdir")) val workDir = defFile?.parentFile ?: File(System.getProperty("java.io.tmpdir"))
ProcessBuilder(*compilerCmd) if (platform == KotlinPlatform.JVM) {
.directory(workDir)
.inheritIO()
.runExpectingSuccess()
File(nativeLibsDir).mkdirs() val outOFile = createTempFile(suffix = ".o")
val outLib = nativeLibsDir + "/" + System.mapLibraryName(libName) val javaHome = System.getProperty("java.home")
val compilerArgsForJniIncludes = listOf("", "linux", "darwin").map { "-I$javaHome/../include/$it" }.toTypedArray()
val linkerCmd = arrayOf("$llvmInstallPath/bin/$linker", *linkerOpts, outOFile.path, "-shared", "-o", outLib, val compilerCmd = arrayOf("$llvmInstallPath/bin/$compiler", *compilerOpts.toTypedArray(),
"-Wl,-flat_namespace,-undefined,dynamic_lookup") *compilerArgsForJniIncludes,
"-c", outCFile.path, "-o", outOFile.path)
ProcessBuilder(*linkerCmd) ProcessBuilder(*compilerCmd)
.directory(workDir) .directory(workDir)
.inheritIO() .inheritIO()
.runExpectingSuccess() .runExpectingSuccess()
val outLib = nativeLibsDir + "/" + System.mapLibraryName(libName)
val linkerCmd = arrayOf("$llvmInstallPath/bin/$linker", *linkerOpts, outOFile.path, "-shared", "-o", outLib,
"-Wl,-flat_namespace,-undefined,dynamic_lookup")
ProcessBuilder(*linkerCmd)
.directory(workDir)
.inheritIO()
.runExpectingSuccess()
outOFile.delete()
} else if (platform == KotlinPlatform.NATIVE) {
val outBcName = libName + ".bc"
val outLib = nativeLibsDir + "/" + outBcName
val compilerCmd = arrayOf("$llvmInstallPath/bin/$compiler", *compilerOpts.toTypedArray(),
"-emit-llvm", "-c", outCFile.path, "-o", outLib)
ProcessBuilder(*compilerCmd)
.directory(workDir)
.inheritIO()
.runExpectingSuccess()
}
outCFile.delete() outCFile.delete()
outOFile.delete()
} }
private fun buildNativeIndex(headerFiles: List<String>, compilerOpts: List<String>): NativeIndex { private fun buildNativeIndex(headerFiles: List<String>, compilerOpts: List<String>): NativeIndex {
+4
View File
@@ -204,9 +204,13 @@ targetList.each { target ->
'-runtime', project(':runtime').file("build/${target}/runtime.bc"), '-runtime', project(':runtime').file("build/${target}/runtime.bc"),
'-properties', project(':backend.native').file('konan.properties'), '-properties', project(':backend.native').file('konan.properties'),
project(':runtime').file('src/main/kotlin'), project(':runtime').file('src/main/kotlin'),
project(':Interop:Runtime').file('src/main/kotlin'),
project(':Interop:Runtime').file('src/native/kotlin'),
*project.globalArgs) *project.globalArgs)
inputs.dir(project(':runtime').file('src/main/kotlin')) inputs.dir(project(':runtime').file('src/main/kotlin'))
inputs.dir(project(':Interop:Runtime').file('src/main/kotlin'))
inputs.dir(project(':Interop:Runtime').file('src/native/kotlin'))
outputs.file(project(':runtime').file("build/${target}/stdlib.kt.bc")) outputs.file(project(':runtime').file("build/${target}/stdlib.kt.bc"))
dependsOn ":runtime:${target}Runtime" dependsOn ":runtime:${target}Runtime"
@@ -62,6 +62,9 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
put(LIBRARY_FILES, put(LIBRARY_FILES,
arguments.libraries.toNonNullList()) arguments.libraries.toNonNullList())
put(NATIVE_LIBRARY_FILES,
arguments.nativeLibraries.toNonNullList())
// TODO: Collect all the explicit file names into an object // TODO: Collect all the explicit file names into an object
// and teach the compiler to work with temporaries and -save-temps. // and teach the compiler to work with temporaries and -save-temps.
val bitcodeFile = if (arguments.nolink) { val bitcodeFile = if (arguments.nolink) {
@@ -21,6 +21,10 @@ public class K2NativeCompilerArguments extends CommonCompilerArguments {
@ValueDescription("<path>") @ValueDescription("<path>")
public String[] libraries; public String[] libraries;
@Argument(value = "nativelibrary", alias = "nl", description = "Link with the native library")
@ValueDescription("<path>")
public String[] nativeLibraries;
@Argument(value = "nolink", description = "Don't link, just produce a bitcode file") @Argument(value = "nolink", description = "Don't link, just produce a bitcode file")
public boolean nolink; public boolean nolink;
@@ -1,38 +1,22 @@
/* package org.jetbrains.kotlin.backend.common.lower
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.common
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression
import org.jetbrains.kotlin.ir.declarations.IrLocalDelegatedProperty
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import java.util.*
abstract class AbstractClosureRecorder : IrElementVisitorVoid { // TODO: synchronize with JVM BE
class Closure(val capturedValues: List<ValueDescriptor>)
abstract class AbstractClosureAnnotator : IrElementVisitorVoid {
protected abstract fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure) protected abstract fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure)
protected abstract fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure) protected abstract fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure)
private class ClosureBuilder(val owner: DeclarationDescriptor) { private abstract class ClosureBuilder(open val owner: DeclarationDescriptor) {
val capturedValues = mutableSetOf<ValueDescriptor>() val capturedValues = mutableSetOf<ValueDescriptor>()
fun buildClosure() = Closure(capturedValues.toList()) fun buildClosure() = Closure(capturedValues.toList())
@@ -43,12 +27,39 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid {
private fun <T : CallableDescriptor> fillInNestedClosure(destination: MutableSet<T>, nested: List<T>) { private fun <T : CallableDescriptor> fillInNestedClosure(destination: MutableSet<T>, nested: List<T>) {
nested.filterTo(destination) { nested.filterTo(destination) {
it.containingDeclaration != owner isExternal(it)
} }
} }
abstract fun <T : CallableDescriptor> isExternal(valueDescriptor: T): Boolean
} }
private val closuresStack = ArrayDeque<ClosureBuilder>() private class FunctionClosureBuilder(override val owner: FunctionDescriptor) : ClosureBuilder(owner) {
override fun <T : CallableDescriptor> isExternal(valueDescriptor: T): Boolean =
valueDescriptor.containingDeclaration != owner && valueDescriptor != owner.dispatchReceiverParameter
}
private class ClassClosureBuilder(override val owner: ClassDescriptor) : ClosureBuilder(owner) {
override fun <T : CallableDescriptor> isExternal(valueDescriptor: T): Boolean {
// TODO: replace with 'return valueDescriptor.containingDeclaration != owner' after constructors lowering.
var declaration: DeclarationDescriptor? = valueDescriptor.containingDeclaration
while (declaration != null && declaration != owner) {
declaration = declaration.containingDeclaration
}
return declaration != owner
}
}
private val closuresStack = mutableListOf<ClosureBuilder>()
private fun <E> MutableList<E>.push(element: E) = this.add(element)
private fun <E> MutableList<E>.pop() = this.removeAt(size - 1)
private fun <E> MutableList<E>.peek(): E? = if (size == 0) null else this[size - 1]
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this) element.acceptChildrenVoid(this)
@@ -56,7 +67,7 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid {
override fun visitClass(declaration: IrClass) { override fun visitClass(declaration: IrClass) {
val classDescriptor = declaration.descriptor val classDescriptor = declaration.descriptor
val closureBuilder = ClosureBuilder(classDescriptor) val closureBuilder = ClassClosureBuilder(classDescriptor)
closuresStack.push(closureBuilder) closuresStack.push(closureBuilder)
declaration.acceptChildrenVoid(this) declaration.acceptChildrenVoid(this)
@@ -73,7 +84,7 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid {
override fun visitFunction(declaration: IrFunction) { override fun visitFunction(declaration: IrFunction) {
val functionDescriptor = declaration.descriptor val functionDescriptor = declaration.descriptor
val closureBuilder = ClosureBuilder(functionDescriptor) val closureBuilder = FunctionClosureBuilder(functionDescriptor)
closuresStack.push(closureBuilder) closuresStack.push(closureBuilder)
declaration.acceptChildrenVoid(this) declaration.acceptChildrenVoid(this)
@@ -98,7 +109,7 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid {
if (closureBuilder != null) { if (closureBuilder != null) {
val variableDescriptor = expression.descriptor val variableDescriptor = expression.descriptor
if (variableDescriptor.containingDeclaration != closureBuilder.owner) { if (closureBuilder.isExternal(variableDescriptor)) {
closureBuilder.capturedValues.add(variableDescriptor) closureBuilder.capturedValues.add(variableDescriptor)
} }
} }
@@ -16,28 +16,32 @@
package org.jetbrains.kotlin.backend.common.lower package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.AbstractClosureRecorder
import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.Closure
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.descriptorUtil.parents import org.jetbrains.kotlin.resolve.descriptorUtil.parents
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import java.util.* import java.util.*
class LocalDeclarationsLowering(val context: BackendContext): DeclarationContainerLoweringPass { class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContainerLoweringPass {
override fun lower(irDeclarationContainer: IrDeclarationContainer) { override fun lower(irDeclarationContainer: IrDeclarationContainer) {
if (irDeclarationContainer is IrDeclaration && if (irDeclarationContainer is IrDeclaration &&
irDeclarationContainer.descriptor.parents.any { it is CallableDescriptor }) { irDeclarationContainer.descriptor.parents.any { it is CallableDescriptor }) {
@@ -51,10 +55,13 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
lambdasCount = 0 lambdasCount = 0
irDeclarationContainer.declarations.transformFlat { memberDeclaration -> irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
if (memberDeclaration is IrFunction) // TODO: may be do the opposite - specify the list of IR elements which need not to be transformed
LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations() when (memberDeclaration) {
else is IrFunction -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
null is IrProperty -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
is IrAnonymousInitializer -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
else -> null
}
} }
} }
@@ -117,7 +124,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
val fieldDescriptor = capturedValueToField[descriptor] ?: return null val fieldDescriptor = capturedValueToField[descriptor] ?: return null
return IrGetFieldImpl(startOffset, endOffset, fieldDescriptor, return IrGetFieldImpl(startOffset, endOffset, fieldDescriptor,
receiver = IrGetValueImpl(startOffset, endOffset, this.descriptor.thisAsReceiverParameter) receiver = IrGetValueImpl(startOffset, endOffset, this.descriptor.thisAsReceiverParameter)
) )
} }
@@ -125,7 +132,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
"LocalClassContext for ${descriptor}" "LocalClassContext for ${descriptor}"
} }
private inner class LocalDeclarationsTransformer(val memberFunction: IrFunction) { private inner class LocalDeclarationsTransformer(val memberDeclaration: IrDeclaration) {
val localFunctions: MutableMap<FunctionDescriptor, LocalFunctionContext> = LinkedHashMap() val localFunctions: MutableMap<FunctionDescriptor, LocalFunctionContext> = LinkedHashMap()
val localClasses: MutableMap<ClassDescriptor, LocalClassContext> = LinkedHashMap() val localClasses: MutableMap<ClassDescriptor, LocalClassContext> = LinkedHashMap()
val localClassConstructors: MutableMap<ClassConstructorDescriptor, LocalClassConstructorContext> = LinkedHashMap() val localClassConstructors: MutableMap<ClassConstructorDescriptor, LocalClassConstructorContext> = LinkedHashMap()
@@ -155,7 +162,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
private fun collectRewrittenDeclarations(): ArrayList<IrDeclaration> = private fun collectRewrittenDeclarations(): ArrayList<IrDeclaration> =
ArrayList<IrDeclaration>(localFunctions.size + localClasses.size + 1).apply { ArrayList<IrDeclaration>(localFunctions.size + localClasses.size + 1).apply {
add(memberFunction) add(memberDeclaration)
localFunctions.values.mapTo(this) { localFunctions.values.mapTo(this) {
val original = it.declaration val original = it.declaration
@@ -174,8 +181,12 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
private inner class FunctionBodiesRewriter(val localContext: LocalContext?) : IrElementTransformerVoid() { private inner class FunctionBodiesRewriter(val localContext: LocalContext?) : IrElementTransformerVoid() {
override fun visitClass(declaration: IrClass): IrStatement { override fun visitClass(declaration: IrClass): IrStatement {
// Replace local class definition with an empty composite. if (declaration.descriptor in localClasses) {
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType) // Replace local class definition with an empty composite.
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
} else {
return super.visitClass(declaration)
}
} }
override fun visitFunction(declaration: IrFunction): IrStatement { override fun visitFunction(declaration: IrFunction): IrStatement {
@@ -183,18 +194,20 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
// Replace local function definition with an empty composite. // Replace local function definition with an empty composite.
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType) return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
} else { } else {
declaration.transformChildrenVoid(this) return super.visitFunction(declaration)
return declaration
} }
} }
override fun visitConstructor(declaration: IrConstructor): IrStatement { override fun visitConstructor(declaration: IrConstructor): IrStatement {
// Body is transformed separately. // Body is transformed separately.
val transformedDescriptor = localClassConstructors[declaration.descriptor]!!.transformedDescriptor val transformedDescriptor = localClassConstructors[declaration.descriptor]?.transformedDescriptor
if (transformedDescriptor != null) {
return IrConstructorImpl(declaration.startOffset, declaration.endOffset, declaration.origin, return IrConstructorImpl(declaration.startOffset, declaration.endOffset, declaration.origin,
transformedDescriptor, declaration.body!!) transformedDescriptor, declaration.body!!)
} else {
return super.visitConstructor(declaration)
}
} }
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
@@ -222,6 +235,21 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
return newCall return newCall
} }
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.transformChildrenVoid(this)
val oldCallee = expression.descriptor.original
val newCallee = transformedDescriptors[oldCallee] as ClassConstructorDescriptor? ?: return expression
val newExpression = IrDelegatingConstructorCallImpl(
expression.startOffset, expression.endOffset,
newCallee,
remapTypeArguments(expression, newCallee)
).fillArguments(expression)
return newExpression
}
private fun <T : IrMemberAccessExpression> T.fillArguments(oldExpression: IrMemberAccessExpression): T { private fun <T : IrMemberAccessExpression> T.fillArguments(oldExpression: IrMemberAccessExpression): T {
mapValueParameters { newValueParameterDescriptor -> mapValueParameters { newValueParameterDescriptor ->
@@ -233,7 +261,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
// The callee expects captured value as argument. // The callee expects captured value as argument.
val capturedValueDescriptor = val capturedValueDescriptor =
newParameterToCaptured[newValueParameterDescriptor] ?: newParameterToCaptured[newValueParameterDescriptor] ?:
throw AssertionError("Non-mapped parameter $newValueParameterDescriptor") throw AssertionError("Non-mapped parameter $newValueParameterDescriptor")
localContext?.irGet( localContext?.irGet(
oldExpression.startOffset, oldExpression.endOffset, oldExpression.startOffset, oldExpression.endOffset,
@@ -292,8 +320,8 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
} }
} }
private fun rewriteFunctionBody(irFunction: IrFunction, localContext: LocalContext?) { private fun rewriteFunctionBody(irDeclaration: IrDeclaration, localContext: LocalContext?) {
irFunction.transformChildrenVoid(FunctionBodiesRewriter(localContext)) irDeclaration.transformChildrenVoid(FunctionBodiesRewriter(localContext))
} }
private object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE : private object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE :
@@ -339,7 +367,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
rewriteClassMembers(it.declaration, it) rewriteClassMembers(it.declaration, it)
} }
rewriteFunctionBody(memberFunction, null) rewriteFunctionBody(memberDeclaration, null)
} }
private fun createNewCall(oldCall: IrCall, newCallee: CallableDescriptor) = private fun createNewCall(oldCall: IrCall, newCallee: CallableDescriptor) =
@@ -395,12 +423,12 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
.toList().reversed() .toList().reversed()
.map { suggestLocalName(it) } .map { suggestLocalName(it) }
.joinToString(separator = "$") .joinToString(separator = "$")
) )
private fun createLiftedDescriptor(localFunctionContext: LocalFunctionContext) { private fun createLiftedDescriptor(localFunctionContext: LocalFunctionContext) {
val oldDescriptor = localFunctionContext.descriptor val oldDescriptor = localFunctionContext.descriptor
val memberOwner = memberFunction.descriptor.containingDeclaration val memberOwner = memberDeclaration.descriptor.containingDeclaration!!
val newDescriptor = SimpleFunctionDescriptorImpl.create( val newDescriptor = SimpleFunctionDescriptorImpl.create(
memberOwner, memberOwner,
oldDescriptor.annotations, oldDescriptor.annotations,
@@ -480,7 +508,15 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
// Do not substitute type parameters for now. // Do not substitute type parameters for now.
val newTypeParameters = oldDescriptor.typeParameters val newTypeParameters = oldDescriptor.typeParameters
val capturedValues = localClassContext.closure.capturedValues val capturedValues = mutableListOf<ValueDescriptor>()
var classDescriptor = oldDescriptor.containingDeclaration
while (true) {
// Capture all values from the hierarchy since we need to call constructor of super class
// with his captured values.
val context = localClasses[classDescriptor] ?: break
capturedValues.addAll(context.closure.capturedValues)
classDescriptor = classDescriptor.getSuperClassOrAny()
}
val newValueParameters = createTransformedValueParameters(localFunctionContext, capturedValues) val newValueParameters = createTransformedValueParameters(localFunctionContext, capturedValues)
@@ -560,8 +596,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
if (valueDescriptor.name.isSpecial) { if (valueDescriptor.name.isSpecial) {
val oldNameStr = valueDescriptor.name.asString() val oldNameStr = valueDescriptor.name.asString()
Name.identifier("$" + oldNameStr.substring(1, oldNameStr.length - 1)) Name.identifier("$" + oldNameStr.substring(1, oldNameStr.length - 1))
} } else
else
valueDescriptor.name valueDescriptor.name
private fun createUnsubstitutedCapturedValueParameter( private fun createUnsubstitutedCapturedValueParameter(
@@ -586,7 +621,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
private fun collectClosures() { private fun collectClosures() {
memberFunction.acceptChildrenVoid(object : AbstractClosureRecorder() { memberDeclaration.acceptChildrenVoid(object : AbstractClosureAnnotator() {
override fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure) { override fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure) {
localFunctions[functionDescriptor]?.closure = closure localFunctions[functionDescriptor]?.closure = closure
} }
@@ -598,16 +633,17 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
} }
private fun collectLocalDeclarations() { private fun collectLocalDeclarations() {
memberFunction.acceptChildrenVoid(object : IrElementVisitorVoid { memberDeclaration.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this) element.acceptChildrenVoid(this)
} }
private fun DeclarationDescriptor.isClassMember() = when (this.containingDeclaration) { private fun DeclarationDescriptor.declaredInFunction() = when (this.containingDeclaration) {
is CallableDescriptor -> false is CallableDescriptor -> true
is ClassDescriptor -> true is ClassDescriptor -> false
else -> TODO(this.toString()) is PackageFragmentDescriptor -> false
else -> TODO(this.toString() + "\n" + this.containingDeclaration.toString())
} }
override fun visitFunction(declaration: IrFunction) { override fun visitFunction(declaration: IrFunction) {
@@ -615,7 +651,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
val descriptor = declaration.descriptor val descriptor = declaration.descriptor
if (!descriptor.isClassMember()) { if (descriptor.declaredInFunction()) {
val localFunctionContext = LocalFunctionContext(declaration) val localFunctionContext = LocalFunctionContext(declaration)
localFunctions[descriptor] = localFunctionContext localFunctions[descriptor] = localFunctionContext
@@ -631,7 +667,9 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
declaration.acceptChildrenVoid(this) declaration.acceptChildrenVoid(this)
val descriptor = declaration.descriptor val descriptor = declaration.descriptor
assert (descriptor.isClassMember()) assert(!descriptor.declaredInFunction())
if (descriptor.constructedClass.isInner) return
localClassConstructors[descriptor] = LocalClassConstructorContext(declaration) localClassConstructors[descriptor] = LocalClassConstructorContext(declaration)
} }
@@ -641,12 +679,13 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
val descriptor = declaration.descriptor val descriptor = declaration.descriptor
if (descriptor.isClassMember()) { if (descriptor.isInner) return
assert (descriptor.isInner)
} else { // Local nested classes can only be inner.
val localClassContext = LocalClassContext(declaration) assert(descriptor.declaredInFunction())
localClasses[descriptor] = localClassContext
} val localClassContext = LocalClassContext(declaration)
localClasses[descriptor] = localClassContext
} }
}) })
} }
@@ -3,6 +3,7 @@ package org.jetbrains.kotlin.backend.konan
import llvm.LLVMDumpModule import llvm.LLVMDumpModule
import llvm.LLVMModuleRef import llvm.LLVMModuleRef
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
import org.jetbrains.kotlin.backend.konan.InteropBuiltIns
import org.jetbrains.kotlin.backend.konan.descriptors.deepPrint import org.jetbrains.kotlin.backend.konan.descriptors.deepPrint
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.Ir import org.jetbrains.kotlin.backend.konan.ir.Ir
@@ -57,6 +58,10 @@ internal final class Context(val config: KonanConfig) : KonanBackendContext() {
override val irBuiltIns override val irBuiltIns
get() = ir.irModule.irBuiltins get() = ir.irModule.irBuiltins
val interopBuiltIns by lazy {
InteropBuiltIns(this.builtIns)
}
var llvmModule: LLVMModuleRef? = null var llvmModule: LLVMModuleRef? = null
set(module: LLVMModuleRef?) { set(module: LLVMModuleRef?) {
if (field != null) { if (field != null) {
@@ -0,0 +1,105 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
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
private val cPointerName = "CPointer"
private val nativePointedName = "NativePointed"
private val nativePtrName = "NativePtr"
internal class InteropBuiltIns(builtIns: KonanBuiltIns) {
object FqNames {
val packageName = FqName("kotlinx.cinterop")
val nativePtr = packageName.child(Name.identifier(nativePtrName)).toUnsafe()
val cPointer = packageName.child(Name.identifier(cPointerName)).toUnsafe()
val nativePointed = packageName.child(Name.identifier(nativePointedName)).toUnsafe()
}
private val packageScope = builtIns.builtInsModule.getPackage(FqNames.packageName).memberScope
val getNativeNullPtr = packageScope.getContributedFunctions("getNativeNullPtr").single()
val getPointerSize = packageScope.getContributedFunctions("getPointerSize").single()
val nullableInteropValueTypes = listOf(ValueType.C_POINTER, ValueType.NATIVE_POINTED)
private val nativePtr = packageScope.getContributedClassifier(nativePtrName) as ClassDescriptor
private val nativePointed = packageScope.getContributedClassifier(nativePointedName) as ClassDescriptor
private val cPointer = this.packageScope.getContributedClassifier(cPointerName) as ClassDescriptor
val cPointerRawValue = cPointer.unsubstitutedMemberScope.getContributedVariables("rawValue").single()
val nativePointedRawPtrGetter =
nativePointed.unsubstitutedMemberScope.getContributedVariables("rawPtr").single().getter!!
val memberAt = packageScope.getContributedFunctions("memberAt").single()
val interpretPointed = packageScope.getContributedFunctions("interpretPointed").single()
val arrayGetByIntIndex = packageScope.getContributedFunctions("get").single {
KotlinBuiltIns.isInt(it.valueParameters.single().type)
}
val arrayGetByLongIndex = packageScope.getContributedFunctions("get").single {
KotlinBuiltIns.isLong(it.valueParameters.single().type)
}
val allocUninitializedArrayWithIntLength = packageScope.getContributedFunctions("allocArray").single {
it.valueParameters.size == 1 && KotlinBuiltIns.isInt(it.valueParameters[0].type)
}
val allocUninitializedArrayWithLongLength = packageScope.getContributedFunctions("allocArray").single {
it.valueParameters.size == 1 && KotlinBuiltIns.isLong(it.valueParameters[0].type)
}
val allocVariable = packageScope.getContributedFunctions("alloc").single {
it.valueParameters.size == 0
}
val typeOf = packageScope.getContributedFunctions("typeOf").single()
val variableClass = packageScope.getContributedClassifier("CVariable") as ClassDescriptor
val variableTypeClass =
variableClass.unsubstitutedInnerClassesScope.getContributedClassifier("Type") as ClassDescriptor
val variableTypeSize = variableTypeClass.unsubstitutedMemberScope.getContributedVariables("size").single()
val variableTypeAlign = variableTypeClass.unsubstitutedMemberScope.getContributedVariables("align").single()
val nativeMemUtils = packageScope.getContributedClassifier("nativeMemUtils") as ClassDescriptor
private val primitives = listOf(
builtIns.byte, builtIns.short, builtIns.int, builtIns.long,
builtIns.float, builtIns.double,
nativePtr
)
val readPrimitive = primitives.map {
nativeMemUtils.unsubstitutedMemberScope.getContributedFunctions("get" + it.name).single()
}.toSet()
val writePrimitive = primitives.map {
nativeMemUtils.unsubstitutedMemberScope.getContributedFunctions("put" + it.name).single()
}.toSet()
val nativePtrPlusLong = nativePtr.unsubstitutedMemberScope.getContributedFunctions("plus").single()
}
private fun MemberScope.getContributedVariables(name: String) =
this.getContributedVariables(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
private fun MemberScope.getContributedClassifier(name: String) =
this.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
private fun MemberScope.getContributedFunctions(name: String) =
this.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
@@ -29,6 +29,9 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
private val loadedDescriptors = loadLibMetadata(libraries) private val loadedDescriptors = loadLibMetadata(libraries)
internal val librariesToLink: List<String>
get() = libraries + configuration.getList(KonanConfigKeys.NATIVE_LIBRARY_FILES)
val moduleId: String val moduleId: String
get() = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME) get() = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)
@@ -7,6 +7,8 @@ class KonanConfigKeys {
companion object { companion object {
val LIBRARY_FILES: CompilerConfigurationKey<List<String>> val LIBRARY_FILES: CompilerConfigurationKey<List<String>>
= CompilerConfigurationKey.create("library file paths") = CompilerConfigurationKey.create("library file paths")
val NATIVE_LIBRARY_FILES: CompilerConfigurationKey<List<String>>
= CompilerConfigurationKey.create("native library file paths")
val BITCODE_FILE: CompilerConfigurationKey<String> val BITCODE_FILE: CompilerConfigurationKey<String>
= CompilerConfigurationKey.create("emitted bitcode file path") = CompilerConfigurationKey.create("emitted bitcode file path")
val EXECUTABLE_FILE: CompilerConfigurationKey<String> val EXECUTABLE_FILE: CompilerConfigurationKey<String>
@@ -23,9 +23,6 @@ internal class KonanLower(val context: Context) {
phaser.phase(KonanPhase.LOWER_ENUMS) { phaser.phase(KonanPhase.LOWER_ENUMS) {
EnumClassLowering(context).run(irFile) EnumClassLowering(context).run(irFile)
} }
phaser.phase(KonanPhase.LOWER_INNER_CLASSES) {
InnerClassLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_VARARG) { phaser.phase(KonanPhase.LOWER_VARARG) {
VarargInjectionLowering(context).runOnFilePostfix(irFile) VarargInjectionLowering(context).runOnFilePostfix(irFile)
} }
@@ -45,6 +42,9 @@ internal class KonanLower(val context: Context) {
phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) { phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) {
LocalDeclarationsLowering(context).runOnFilePostfix(irFile) LocalDeclarationsLowering(context).runOnFilePostfix(irFile)
} }
phaser.phase(KonanPhase.LOWER_INNER_CLASSES) {
InnerClassLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_CALLABLES) { phaser.phase(KonanPhase.LOWER_CALLABLES) {
CallableReferenceLowering(context).runOnFilePostfix(irFile) CallableReferenceLowering(context).runOnFilePostfix(irFile)
} }
@@ -18,6 +18,7 @@ enum class KonanPhase(val description: String,
/* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering"), /* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering"),
/* ... ... */ LOWER_CALLABLES("Callable references Lowering"), /* ... ... */ LOWER_CALLABLES("Callable references Lowering"),
/* ... ... */ LOWER_INLINE("Functions inlining"), /* ... ... */ LOWER_INLINE("Functions inlining"),
/* ... ... */ LOWER_INTEROP("Interop lowering"),
/* ... ... */ AUTOBOX("Autoboxing of primitive types"), /* ... ... */ AUTOBOX("Autoboxing of primitive types"),
/* ... ... */ LOWER_ENUMS("Enum classes lowering"), /* ... ... */ LOWER_ENUMS("Enum classes lowering"),
/* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering"), /* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering"),
@@ -144,7 +144,7 @@ internal class LinkStage(val context: Context) {
val optimize = config.get(KonanConfigKeys.OPTIMIZATION) ?: false val optimize = config.get(KonanConfigKeys.OPTIMIZATION) ?: false
val emitted = config.get(KonanConfigKeys.BITCODE_FILE)!! val emitted = config.get(KonanConfigKeys.BITCODE_FILE)!!
val nostdlib = config.get(KonanConfigKeys.NOSTDLIB) ?: false val nostdlib = config.get(KonanConfigKeys.NOSTDLIB) ?: false
val libraries = context.config.libraries val libraries = context.config.librariesToLink
fun llvmLto(files: List<BitcodeFile>): ObjectFile { fun llvmLto(files: List<BitcodeFile>): ObjectFile {
val tmpCombined = File.createTempFile("combined", ".o") val tmpCombined = File.createTempFile("combined", ".o")
@@ -24,7 +24,11 @@ enum class ValueType(val classFqName: FqNameUnsafe, val isNullable: Boolean = fa
FLOAT(KotlinBuiltIns.FQ_NAMES._float), FLOAT(KotlinBuiltIns.FQ_NAMES._float),
DOUBLE(KotlinBuiltIns.FQ_NAMES._double), DOUBLE(KotlinBuiltIns.FQ_NAMES._double),
UNBOUND_CALLABLE_REFERENCE(FqNameUnsafe("konan.internal.UnboundCallableReference")) UNBOUND_CALLABLE_REFERENCE(FqNameUnsafe("konan.internal.UnboundCallableReference")),
NATIVE_PTR(InteropBuiltIns.FqNames.nativePtr),
NATIVE_POINTED(InteropBuiltIns.FqNames.nativePointed, isNullable = true),
C_POINTER(InteropBuiltIns.FqNames.cPointer, isNullable = true)
} }
private fun KotlinType.isConstructedFromGivenClass(fqName: FqNameUnsafe) = private fun KotlinType.isConstructedFromGivenClass(fqName: FqNameUnsafe) =
@@ -65,6 +65,8 @@ internal fun IrMemberAccessExpression.addArguments(args: Map<ParameterDescriptor
internal fun IrMemberAccessExpression.addArguments(args: List<Pair<ParameterDescriptor, IrExpression>>) = internal fun IrMemberAccessExpression.addArguments(args: List<Pair<ParameterDescriptor, IrExpression>>) =
this.addArguments(args.toMap()) this.addArguments(args.toMap())
internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrConstKind.Null
fun ir2string(ir: IrElement?): String = ir2stringWhole(ir).takeWhile { it != '\n' } fun ir2string(ir: IrElement?): String = ir2stringWhole(ir).takeWhile { it != '\n' }
fun ir2stringWhole(ir: IrElement?): String { fun ir2stringWhole(ir: IrElement?): String {
@@ -15,7 +15,9 @@ private val valueTypes = ValueType.values().associate {
ValueType.LONG -> LLVMInt64Type() ValueType.LONG -> LLVMInt64Type()
ValueType.FLOAT -> LLVMFloatType() ValueType.FLOAT -> LLVMFloatType()
ValueType.DOUBLE -> LLVMDoubleType() ValueType.DOUBLE -> LLVMDoubleType()
ValueType.UNBOUND_CALLABLE_REFERENCE -> int8TypePtr
ValueType.UNBOUND_CALLABLE_REFERENCE,
ValueType.NATIVE_PTR, ValueType.NATIVE_POINTED, ValueType.C_POINTER -> int8TypePtr
}!! }!!
} }
@@ -625,7 +625,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
private fun evaluateExpression(value: IrExpression): LLVMValueRef { private fun evaluateExpression(value: IrExpression): LLVMValueRef {
when (value) { when (value) {
is IrSetterCallImpl -> return evaluateSetterCall (value)
is IrTypeOperatorCall -> return evaluateTypeOperator (value) is IrTypeOperatorCall -> return evaluateTypeOperator (value)
is IrCall -> return evaluateCall (value) is IrCall -> return evaluateCall (value)
is IrDelegatingConstructorCall -> is IrDelegatingConstructorCall ->
@@ -1742,18 +1741,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
return callDirect(descriptor, args, resultLifetime) return callDirect(descriptor, args, resultLifetime)
} }
//-------------------------------------------------------------------------//
private fun evaluateSetterCall(value: IrSetterCallImpl): LLVMValueRef {
val descriptor = value.descriptor as FunctionDescriptor
val args = mutableListOf<LLVMValueRef>()
if (descriptor.dispatchReceiverParameter != null)
args.add(evaluateExpression(value.dispatchReceiver!!)) //add this ptr
args.add(evaluateExpression(value.getValueArgument(0)!!))
return evaluateSimpleFunctionCall(
descriptor, args, Lifetime.IRRELEVANT, value.superQualifier)
}
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun resultLifetime(callee: IrMemberAccessExpression): Lifetime { private fun resultLifetime(callee: IrMemberAccessExpression): Lifetime {
return resultLifetimes.getOrElse(callee) { Lifetime.GLOBAL } return resultLifetimes.getOrElse(callee) { Lifetime.GLOBAL }
@@ -1779,16 +1766,16 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun evaluateIntrinsicCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef { private fun evaluateIntrinsicCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
val descriptor = callee.descriptor val descriptor = callee.descriptor.original
val name = descriptor.fqNameUnsafe.asString() val name = descriptor.fqNameUnsafe.asString()
return when (name) { when (name) {
"konan.internal.areEqualByValue" -> { "konan.internal.areEqualByValue" -> {
val arg0 = args[0] val arg0 = args[0]
val arg1 = args[1] val arg1 = args[1]
assert (arg0.type == arg1.type) assert (arg0.type == arg1.type)
when (LLVMGetTypeKind(arg0.type)) { return when (LLVMGetTypeKind(arg0.type)) {
LLVMTypeKind.LLVMFloatTypeKind, LLVMTypeKind.LLVMDoubleTypeKind -> LLVMTypeKind.LLVMFloatTypeKind, LLVMTypeKind.LLVMDoubleTypeKind ->
codegen.fcmpEq(arg0, arg1) codegen.fcmpEq(arg0, arg1)
@@ -1796,8 +1783,28 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
codegen.icmpEq(arg0, arg1) codegen.icmpEq(arg0, arg1)
} }
} }
}
else -> TODO(name) val interop = context.interopBuiltIns
return when (descriptor) {
in interop.readPrimitive -> {
val pointerType = pointerType(codegen.getLLVMType(descriptor.returnType!!))
val rawPointer = args.last()
val pointer = codegen.bitcast(pointerType, rawPointer)
codegen.load(pointer)
}
in interop.writePrimitive -> {
val pointerType = pointerType(codegen.getLLVMType(descriptor.valueParameters.last().type))
val rawPointer = args[1]
val pointer = codegen.bitcast(pointerType, rawPointer)
codegen.store(args[2], pointer)
codegen.theUnitInstanceRef.llvm
}
interop.nativePtrPlusLong -> codegen.gep(args[0], args[1])
interop.getNativeNullPtr -> kNullInt8Ptr
interop.getPointerSize -> Int32(LLVMPointerSize(codegen.llvmTargetData)).llvm
else -> TODO(callee.descriptor.original.toString())
} }
} }
@@ -6,8 +6,10 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.ValueType import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalClass import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalClass
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
import org.jetbrains.kotlin.backend.konan.ir.isNullConst
import org.jetbrains.kotlin.backend.konan.notNullableIsRepresentedAs import org.jetbrains.kotlin.backend.konan.notNullableIsRepresentedAs
import org.jetbrains.kotlin.backend.konan.isRepresentedAs import org.jetbrains.kotlin.backend.konan.isRepresentedAs
import org.jetbrains.kotlin.backend.konan.util.atMostOne
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
@@ -103,6 +105,10 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
} }
override fun IrExpression.useAs(type: KotlinType): IrExpression { override fun IrExpression.useAs(type: KotlinType): IrExpression {
val interop = context.interopBuiltIns
if (this.isNullConst() && interop.nullableInteropValueTypes.any { type.isRepresentedAs(it) }) {
return IrCallImpl(startOffset, endOffset, interop.getNativeNullPtr).uncheckedCast(type)
}
val actualType = when (this) { val actualType = when (this) {
is IrCall -> this.descriptor.original.returnType ?: this.type is IrCall -> this.descriptor.original.returnType ?: this.type
@@ -176,6 +182,14 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
} }
private fun IrExpression.unbox(valueType: ValueType): IrExpression { private fun IrExpression.unbox(valueType: ValueType): IrExpression {
val unboxFunctionName = "unbox${valueType.shortName}"
context.builtIns.getKonanInternalFunctions(unboxFunctionName).atMostOne()?.let {
return IrCallImpl(startOffset, endOffset, it).apply {
putValueArgument(0, this@unbox.uncheckedCast(it.valueParameters[0].type))
}.uncheckedCast(this.type)
}
val boxGetter = getBoxType(valueType) val boxGetter = getBoxType(valueType)
.memberScope.getContributedDescriptors() .memberScope.getContributedDescriptors()
.filterIsInstance<PropertyDescriptor>() .filterIsInstance<PropertyDescriptor>()
@@ -3,6 +3,8 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
import org.jetbrains.kotlin.backend.konan.ir.isNullConst
import org.jetbrains.kotlin.backend.konan.util.atMostOne
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptor import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptor
import org.jetbrains.kotlin.ir.expressions.IrBody import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
@@ -69,9 +71,15 @@ private class BuiltinOperatorTransformer(val context: Context) : IrElementTransf
// and thus can be declared synthetically in the compiler instead of explicitly in the runtime. // and thus can be declared synthetically in the compiler instead of explicitly in the runtime.
// Find a type-compatible `konan.internal.areEqualByValue` intrinsic: // Find a type-compatible `konan.internal.areEqualByValue` intrinsic:
val equals = builtIns.getKonanInternalFunctions("areEqualByValue").firstOrNull { val equals = builtIns.getKonanInternalFunctions("areEqualByValue").atMostOne {
lhs.type.isSubtypeOf(it.valueParameters[0].type) && rhs.type.isSubtypeOf(it.valueParameters[1].type) lhs.type.isSubtypeOf(it.valueParameters[0].type) && rhs.type.isSubtypeOf(it.valueParameters[1].type)
} ?: builtIns.getKonanInternalFunctions("areEqual").single() // or use the general implementation. } ?: if (lhs.isNullConst() || rhs.isNullConst()) {
// or compare by reference if left or right part is `null`:
irBuiltins.eqeqeq
} else {
// or use the general implementation:
builtIns.getKonanInternalFunctions("areEqual").single()
}
return IrCallImpl(startOffset, endOffset, equals).apply { return IrCallImpl(startOffset, endOffset, equals).apply {
putValueArgument(0, lhs) putValueArgument(0, lhs)
@@ -69,7 +69,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
if (instanceInitializerIndex >= 0) { if (instanceInitializerIndex >= 0) {
// Initializing constructor: initialize 'this.this$0' with '$outer'. // Initializing constructor: initialize 'this.this$0' with '$outer'.
blockBody.statements.add( blockBody.statements.add(
instanceInitializerIndex, 0,
IrSetFieldImpl( IrSetFieldImpl(
startOffset, endOffset, outerThisFieldDescriptor, startOffset, endOffset, outerThisFieldDescriptor,
IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter), IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter),
@@ -117,7 +117,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
val outerThisField = context.specialDescriptorsFactory.getOuterThisFieldDescriptor(innerClass) val outerThisField = context.specialDescriptorsFactory.getOuterThisFieldDescriptor(innerClass)
irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField, irThis, origin) irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField, irThis, origin)
val outer = classDescriptor.containingDeclaration val outer = innerClass.containingDeclaration
innerClass = outer as? ClassDescriptor ?: innerClass = outer as? ClassDescriptor ?:
throw AssertionError("Unexpected containing declaration for inner class $innerClass: $outer") throw AssertionError("Unexpected containing declaration for inner class $innerClass: $outer")
} }
@@ -0,0 +1,201 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.backend.common.lower.createFunctionIrBuilder
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.isRepresentedAs
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.builders.IrBuilder
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
/**
* Lowers some interop intrinsic calls.
*/
internal class InteropLowering(val context: Context) : FunctionLoweringPass {
override fun lower(irFunction: IrFunction) {
val transformer = InteropTransformer(context, irFunction.descriptor)
irFunction.transformChildrenVoid(transformer)
}
}
private class InteropTransformer(val context: Context, val function: FunctionDescriptor) : IrElementTransformerVoid() {
val builder = context.createFunctionIrBuilder(function)
val interop = context.interopBuiltIns
private fun MemberScope.getSingleContributedFunction(name: String,
predicate: (SimpleFunctionDescriptor) -> Boolean) =
this.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single(predicate)
private fun IrBuilder.irGetObject(descriptor: ClassDescriptor): IrExpression {
return IrGetObjectValueImpl(startOffset, endOffset, descriptor.defaultType, descriptor)
}
private fun IrBuilder.typeOf(descriptor: ClassDescriptor): IrExpression {
val companionObject = descriptor.companionObjectDescriptor ?:
error("native variable class $descriptor must have the companion object")
// TODO: add more checks and produce the compile error instead of exception.
return irGetObject(companionObject)
}
private fun IrBuilder.typeOf(type: KotlinType): IrExpression? {
val descriptor = TypeUtils.getClassDescriptor(type) ?: return null
return typeOf(descriptor)
}
private fun KotlinType.findOverride(property: PropertyDescriptor): PropertyDescriptor {
val result = this.memberScope.getContributedVariables(property.name, NoLookupLocation.FROM_BACKEND).single()
assert (OverridingUtil.overrides(result, property))
return result
}
private fun IrBuilderWithScope.sizeOf(typeObject: IrExpression): IrExpression {
val sizeProperty = typeObject.type.findOverride(interop.variableTypeSize)
return irGet(typeObject, sizeProperty)
}
private fun IrBuilderWithScope.sizeOf(type: KotlinType): IrExpression? {
val typeObject = typeOf(type) ?: return null
return sizeOf(typeObject)
}
private fun IrBuilderWithScope.alignOf(typeObject: IrExpression): IrExpression {
val alignProperty = typeObject.type.findOverride(interop.variableTypeAlign)
return irGet(typeObject, alignProperty)
}
private fun IrBuilderWithScope.alignOf(type: KotlinType): IrExpression? {
val typeObject = typeOf(type) ?: return null
return alignOf(typeObject)
}
private fun IrBuilderWithScope.arrayGet(array: IrExpression, index: IrExpression): IrExpression? {
val elementSize = sizeOf(array.type.arguments.single().type) ?: return null
val offset = times(elementSize, index)
return irCall(interop.memberAt).apply {
extensionReceiver = array
putValueArgument(0, offset)
}
}
private fun IrBuilderWithScope.times(left: IrExpression, right: IrExpression): IrCall {
val times = left.type.memberScope.getSingleContributedFunction("times") {
right.type.isSubtypeOf(it.valueParameters.single().type)
}
return irCall(times).apply {
dispatchReceiver = left
putValueArgument(0, right)
}
}
private fun IrBuilderWithScope.alloc(placement: IrExpression, size: IrExpression, align: IrExpression): IrExpression {
val alloc = placement.type.memberScope.getSingleContributedFunction("alloc") {
size.type.isSubtypeOf(it.valueParameters[0]!!.type) &&
align.type.isSubtypeOf(it.valueParameters[1]!!.type)
}
return irCall(alloc).apply {
dispatchReceiver = placement
putValueArgument(0, size)
putValueArgument(1, align)
}
}
private fun IrBuilderWithScope.allocArray(placement: IrExpression,
elementType: KotlinType,
length: IrExpression
): IrExpression? {
val elementSize = sizeOf(elementType) ?: return null
val size = times(elementSize, length)
val align = alignOf(elementType) ?: return null
return alloc(placement, size, align)
}
private fun IrBuilderWithScope.alloc(placement: IrExpression, type: KotlinType): IrExpression? {
val size = sizeOf(type) ?: return null
val align = alignOf(type) ?: return null
return alloc(placement, size, align)
}
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
builder.at(expression)
val descriptor = expression.descriptor.original
if (descriptor is ClassConstructorDescriptor) {
val type = descriptor.constructedClass.defaultType
if (type.isRepresentedAs(ValueType.C_POINTER) || type.isRepresentedAs(ValueType.NATIVE_POINTED)) {
return expression.getValueArgument(0)!!
}
}
if (descriptor == interop.nativePointedRawPtrGetter ||
OverridingUtil.overrides(descriptor, interop.nativePointedRawPtrGetter)) {
return expression.dispatchReceiver!!
}
return when (descriptor) {
interop.cPointerRawValue.getter -> expression.dispatchReceiver!!
interop.interpretPointed -> expression.getValueArgument(0)!!
interop.arrayGetByIntIndex, interop.arrayGetByLongIndex -> {
val array = expression.extensionReceiver!!
val index = expression.getValueArgument(0)!!
builder.arrayGet(array, index) ?: expression
}
interop.allocUninitializedArrayWithIntLength, interop.allocUninitializedArrayWithLongLength -> {
val placement = expression.extensionReceiver!!
val elementType = expression.type.arguments.single().type
val length = expression.getValueArgument(0)!!
builder.allocArray(placement, elementType, length) ?: expression
}
interop.allocVariable -> {
val placement = expression.extensionReceiver!!
val type = expression.getSingleTypeArgument()
builder.alloc(placement, type) ?: expression
}
interop.typeOf -> {
val type = expression.getSingleTypeArgument()
builder.typeOf(type) ?: expression
}
else -> expression
}
}
private fun IrCall.getSingleTypeArgument(): KotlinType {
val typeParameter = descriptor.original.typeParameters.single()
return getTypeArgument(typeParameter)!!
}
}
@@ -20,3 +20,12 @@ fun nTabs(amount: Int): String {
return String.format("%1$-${(amount+1)*4}s", "") return String.format("%1$-${(amount+1)*4}s", "")
} }
fun <T> Collection<T>.atMostOne(): T? {
return when (this.size) {
0 -> null
1 -> this.iterator().next()
else -> throw IllegalArgumentException("Collection has more than one element.")
}
}
inline fun <T> Iterable<T>.atMostOne(predicate: (T) -> Boolean): T? = this.filter(predicate).atMostOne()
+51 -4
View File
@@ -1,6 +1,8 @@
import groovy.json.JsonOutput import groovy.json.JsonOutput
import org.jetbrains.kotlin.* import org.jetbrains.kotlin.*
apply plugin: NativeInteropPlugin
configurations { configurations {
cli_bc cli_bc
} }
@@ -357,11 +359,46 @@ task innerClass_generic(type: RunKonanTest) {
source = "codegen/innerClass/generic.kt" source = "codegen/innerClass/generic.kt"
} }
task innerClass_doubleInner(type: RunKonanTest) {
goldValue = "OK\n"
source = "codegen/innerClass/doubleInner.kt"
}
task innerClass_qualifiedThis(type: RunKonanTest) { task innerClass_qualifiedThis(type: RunKonanTest) {
goldValue = "OK\n" goldValue = "OK\n"
source = "codegen/innerClass/qualifiedThis.kt" source = "codegen/innerClass/qualifiedThis.kt"
} }
task innerClass_superOuter(type: RunKonanTest) {
goldValue = "OK\n"
source = "codegen/innerClass/superOuter.kt"
}
task localClass_localHierarchy(type: RunKonanTest) {
goldValue = "OK\n"
source = "codegen/localClass/localHierarchy.kt"
}
task localClass_objectExpressionInProperty(type: RunKonanTest) {
goldValue = "OK\n"
source = "codegen/localClass/objectExpressionInProperty.kt"
}
task localClass_objectExpressionInInitializer(type: RunKonanTest) {
goldValue = "OK\n"
source = "codegen/localClass/objectExpressionInInitializer.kt"
}
task localClass_innerWithCapture(type: RunKonanTest) {
goldValue = "OK\n"
source = "codegen/localClass/innerWithCapture.kt"
}
task localClass_innerTakesCapturedFromOuter(type: RunKonanTest) {
goldValue = "0\n1\n"
source = "codegen/localClass/innerTakesCapturedFromOuter.kt"
}
task array0(type: RunKonanTest) { task array0(type: RunKonanTest) {
goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n" goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n"
source = "runtime/collections/array0.kt" source = "runtime/collections/array0.kt"
@@ -1023,10 +1060,6 @@ task inline9(type: RunKonanTest) {
source = "codegen/inline/inline9.kt" source = "codegen/inline/inline9.kt"
} }
task vararg0(type: RunKonanTest) {
source = "lower/vararg.kt"
}
task inline6(type: RunKonanTest) { task inline6(type: RunKonanTest) {
goldValue = "hello1\nhello2\nhello3\nhello4\n" goldValue = "hello1\nhello2\nhello3\nhello4\n"
source = "codegen/inline/inline6.kt" source = "codegen/inline/inline6.kt"
@@ -1041,3 +1074,17 @@ task inline8(type: RunKonanTest) {
goldValue = "8\n" goldValue = "8\n"
source = "codegen/inline/inline8.kt" source = "codegen/inline/inline8.kt"
} }
kotlinNativeInterop {
sysstat {
pkg 'sysstat'
headers 'sys/stat.h'
target 'native'
}
}
task interop0(type: RunInteropKonanTest) {
goldValue = "0\n0\n"
source = "interop/basics/0.kt"
interop = 'sysstat'
}
@@ -0,0 +1,21 @@
open class Father(val param: String) {
abstract inner class InClass {
fun work(): String {
return param
}
}
inner class Child(p: String) : Father(p) {
inner class Child2 : Father.InClass {
constructor(): super()
}
}
}
fun box(): String {
return Father("fail").Child("OK").Child2().work()
}
fun main(args: Array<String>) {
println(box())
}
@@ -0,0 +1,13 @@
open class Outer(val outer: String) {
open inner class Inner(val inner: String): Outer(inner) {
fun foo() = outer
}
fun value() = Inner("OK").foo()
}
fun box() = Outer("Fail").value()
fun main(args : Array<String>) {
println(box())
}
@@ -0,0 +1,18 @@
fun box() {
var previous: Any? = null
for (i in 0 .. 2) {
class Outer {
inner class Inner {
override fun toString() = i.toString()
}
override fun toString() = Inner().toString()
}
if (previous != null) println(previous.toString())
previous = Outer()
}
}
fun main(args: Array<String>) {
box()
}
@@ -0,0 +1,13 @@
fun box(s: String): String {
class Local {
open inner class Inner() {
open fun result() = s
}
}
return Local().Inner().result()
}
fun main(args : Array<String>) {
println(box("OK"))
}
@@ -0,0 +1,15 @@
fun foo(s: String): String {
open class Local {
fun f() = s
}
open class Derived: Local() {
fun g() = f()
}
return Derived().g()
}
fun main(args: Array<String>) {
println(foo("OK"))
}
@@ -0,0 +1,25 @@
abstract class Father {
abstract inner class InClass {
abstract fun work(): String
}
}
class Child : Father() {
val ChildInClass : InClass
init {
ChildInClass = object : Father.InClass() {
override fun work(): String {
return "OK"
}
}
}
}
fun box(): String {
return Child().ChildInClass.work()
}
fun main(args: Array<String>) {
println(box())
}
@@ -0,0 +1,21 @@
abstract class Father {
abstract inner class InClass {
abstract fun work(): String
}
}
class Child : Father() {
val ChildInClass = object : Father.InClass() {
override fun work(): String {
return "OK"
}
}
}
fun box(): String {
return Child().ChildInClass.work()
}
fun main(args: Array<String>) {
println(box())
}
@@ -6,7 +6,7 @@
open class Outer(vararg val chars: Char) { open class Outer(vararg val chars: Char) {
open inner class Inner(val s: String): Outer(s[0], s[1]) { open inner class Inner(val s: String): Outer(s[0], s[1]) {
fun concat() = java.lang.String.valueOf(chars) fun concat() = fromCharArrays(chars, 0, chars.size)
} }
fun value() = Inner("OK").concat() fun value() = Inner("OK").concat()
+9
View File
@@ -0,0 +1,9 @@
import sysstat.*
import kotlinx.cinterop.*
fun main(args: Array<String>) {
val statBuf = nativeHeap.alloc<statStruct>()
val res = stat("/", statBuf.ptr)
println(res)
println(statBuf.st_uid.value)
}
@@ -158,6 +158,28 @@ class RunKonanTest extends KonanTest {
} }
} }
@ParallelizableTask
class RunInteropKonanTest extends KonanTest {
private String interop
private NamedNativeInteropConfig interopConf
void setInterop(String value) {
this.interop = value
this.interopConf = project.kotlinNativeInterop[value]
this.dependsOn(this.interopConf.genTask)
}
void compileTest(List<String> filesToCompile, String exe) {
String interopBc = exe + "-interop.bc"
runCompiler([interopConf.generatedSrcDir.absolutePath], interopBc, ["-nolink"])
String interopStubsBc = new File(interopConf.nativeLibsDir, interop + "stubs.bc").absolutePath
runCompiler(filesToCompile, exe, ["-library", interopBc, "-nativelibrary", interopStubsBc])
}
}
@ParallelizableTask @ParallelizableTask
class LinkKonanTest extends KonanTest { class LinkKonanTest extends KonanTest {
protected String lib protected String lib
@@ -18,15 +18,19 @@ class NamedNativeInteropConfig implements Named {
private final Project project private final Project project
final String name final String name
private final SourceSet interopStubs
private final JavaExec genTask private String interopStubsName
private SourceSet interopStubs
final JavaExec genTask
private String target = "jvm"
private String defFile private String defFile
private String pkg; private String pkg;
private List<String> compilerOpts = [] private List<String> compilerOpts = []
private FileCollection headers; private List<String> headers;
private String linker private String linker
private List<String> linkerOpts = [] private List<String> linkerOpts = []
private FileCollection linkFiles; private FileCollection linkFiles;
@@ -34,6 +38,10 @@ class NamedNativeInteropConfig implements Named {
Configuration configuration Configuration configuration
void target(String value) {
target = value
}
void defFile(String value) { void defFile(String value) {
defFile = value defFile = value
genTask.inputs.file(project.file(defFile)) genTask.inputs.file(project.file(defFile))
@@ -49,7 +57,11 @@ class NamedNativeInteropConfig implements Named {
void headers(FileCollection files) { void headers(FileCollection files) {
dependsOnFiles(files) dependsOnFiles(files)
headers = headers + files headers = headers + files.toSet().collect { it.absolutePath }
}
void headers(String... values) {
headers = headers + values.toList()
} }
void linker(String value) { void linker(String value) {
@@ -107,11 +119,11 @@ class NamedNativeInteropConfig implements Named {
compilerOpts.addAll(values.collect {"-I$it"}) compilerOpts.addAll(values.collect {"-I$it"})
} }
private File getNativeLibsDir() { File getNativeLibsDir() {
return new File(project.buildDir, "nativelibs") return new File(project.buildDir, "nativelibs")
} }
private File getGeneratedSrcDir() { File getGeneratedSrcDir() {
return new File(project.buildDir, "nativeInteropStubs/$name/kotlin") return new File(project.buildDir, "nativeInteropStubs/$name/kotlin")
} }
@@ -119,25 +131,31 @@ class NamedNativeInteropConfig implements Named {
this.name = name this.name = name
this.project = project this.project = project
this.headers = project.files() this.headers = []
this.linkFiles = project.files() this.linkFiles = project.files()
interopStubs = project.sourceSets.create(name + "InteropStubs") interopStubsName = name + "InteropStubs"
genTask = project.task(interopStubs.getTaskName("gen", ""), type: JavaExec) genTask = project.task("gen" + interopStubsName.capitalize(), type: JavaExec)
configuration = project.configurations.create(interopStubs.name)
this.configure() this.configure()
} }
private void configure() { private void configure() {
project.tasks.getByName(interopStubs.getTaskName("compile", "Kotlin")) { if (project.plugins.hasPlugin("kotlin")) {
dependsOn genTask interopStubs = project.sourceSets.create(interopStubsName)
} configuration = project.configurations.create(interopStubs.name)
project.tasks.getByName(interopStubs.getTaskName("compile", "Kotlin")) {
dependsOn genTask
}
interopStubs.kotlin.srcDirs generatedSrcDir interopStubs.kotlin.srcDirs generatedSrcDir
project.dependencies { project.dependencies {
add interopStubs.getCompileConfigurationName(), project(path: ':Interop:Runtime') add interopStubs.getCompileConfigurationName(), project(path: ':Interop:Runtime')
}
this.configuration.extendsFrom project.configurations[interopStubs.runtimeConfigurationName]
project.dependencies.add(this.configuration.name, interopStubs.output)
} }
genTask.configure { genTask.configure {
@@ -166,6 +184,9 @@ class NamedNativeInteropConfig implements Named {
linkerOpts += linkFiles.files linkerOpts += linkFiles.files
args = [generatedSrcDir, nativeLibsDir] args = [generatedSrcDir, nativeLibsDir]
args "-target:" + this.target
if (defFile != null) { if (defFile != null) {
args "-def:" + project.file(defFile) args "-def:" + project.file(defFile)
} }
@@ -188,7 +209,7 @@ class NamedNativeInteropConfig implements Named {
args compilerOpts.collect { "-copt:$it" } args compilerOpts.collect { "-copt:$it" }
args linkerOpts.collect { "-lopt:$it" } args linkerOpts.collect { "-lopt:$it" }
headers.files.each { headers.each {
args "-h:$it" args "-h:$it"
} }
@@ -198,9 +219,6 @@ class NamedNativeInteropConfig implements Named {
} }
} }
this.configuration.extendsFrom project.configurations[interopStubs.runtimeConfigurationName]
project.dependencies.add(this.configuration.name, interopStubs.output)
} }
} }
+21
View File
@@ -1,3 +1,6 @@
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@@ -187,4 +190,22 @@ OBJ_GETTER0(Kotlin_konan_internal_undefined) {
RETURN_OBJ(nullptr); RETURN_OBJ(nullptr);
} }
void* Kotlin_interop_malloc(KLong size, KInt align) {
if (size > SIZE_MAX) {
return nullptr;
}
void* result = malloc(size);
if ((reinterpret_cast<uintptr_t>(result) & (align - 1)) != 0) {
// Unaligned!
RuntimeAssert(false, "unsupported alignment");
}
return result;
}
void Kotlin_interop_free(void* ptr) {
free(ptr);
}
} // extern "C" } // extern "C"
@@ -24,13 +24,6 @@ annotation class ExportTypeInfo(val name: String)
public annotation class Used public annotation class Used
// Following annotations can be used to mark functions that need to be fixed,
// once certain language feature is implemented.
/**
* Need to be fixed because of inner classes.
*/
public annotation class FixmeInner
/** /**
* Need to be fixed because of reification support. * Need to be fixed because of reification support.
*/ */
@@ -0,0 +1,53 @@
package konan.internal
import kotlinx.cinterop.*
class NativePtrBox(val value: NativePtr) {
override fun equals(other: Any?): Boolean {
if (other !is NativePtrBox) {
return false
}
return this.value == other.value
}
override fun hashCode() = value.hashCode()
override fun toString() = value.toString()
}
fun boxNativePtr(value: NativePtr) = NativePtrBox(value)
class NativePointedBox(val value: NativePointed) {
override fun equals(other: Any?): Boolean {
if (other !is NativePointedBox) {
return false
}
return this.value == other.value
}
override fun hashCode() = value.hashCode()
override fun toString() = value.toString()
}
fun boxNativePointed(value: NativePointed?) = if (value != null) NativePointedBox(value) else null
fun unboxNativePointed(box: NativePointedBox?) = box?.value
class CPointerBox(val value: CPointer<*>) {
override fun equals(other: Any?): Boolean {
if (other !is CPointerBox) {
return false
}
return this.value == other.value
}
override fun hashCode() = value.hashCode()
override fun toString() = value.toString()
}
fun boxCPointer(value: CPointer<*>?) = if (value != null) CPointerBox(value) else null
fun unboxCPointer(box: CPointerBox?) = box?.value
@@ -1,5 +1,9 @@
package konan.internal package konan.internal
import kotlinx.cinterop.CPointer
import kotlinx.cinterop.NativePointed
import kotlinx.cinterop.NativePtr
@Intrinsic external fun areEqualByValue(first: Boolean, second: Boolean): Boolean @Intrinsic external fun areEqualByValue(first: Boolean, second: Boolean): Boolean
@Intrinsic external fun areEqualByValue(first: Char, second: Char): Boolean @Intrinsic external fun areEqualByValue(first: Char, second: Char): Boolean
@Intrinsic external fun areEqualByValue(first: Byte, second: Byte): Boolean @Intrinsic external fun areEqualByValue(first: Byte, second: Byte): Boolean
@@ -9,9 +13,9 @@ package konan.internal
@Intrinsic external fun areEqualByValue(first: Float, second: Float): Boolean @Intrinsic external fun areEqualByValue(first: Float, second: Float): Boolean
@Intrinsic external fun areEqualByValue(first: Double, second: Double): Boolean @Intrinsic external fun areEqualByValue(first: Double, second: Double): Boolean
// For comparing with `null`: @Intrinsic external fun areEqualByValue(first: NativePtr, second: NativePtr): Boolean
@Intrinsic external fun areEqualByValue(first: Nothing?, second: Any?): Boolean @Intrinsic external fun areEqualByValue(first: NativePointed?, second: NativePointed?): Boolean
@Intrinsic external fun areEqualByValue(first: Any?, second: Nothing?): Boolean @Intrinsic external fun areEqualByValue(first: CPointer<*>?, second: CPointer<*>?): Boolean
inline fun areEqual(first: Any?, second: Any?): Boolean { inline fun areEqual(first: Any?, second: Any?): Boolean {
return if (first == null) second == null else first.equals(second) return if (first == null) second == null else first.equals(second)
@@ -154,3 +154,12 @@ public class NoWhenBranchMatchedException : RuntimeException {
constructor(s: String) : super(s) { constructor(s: String) : super(s) {
} }
} }
public class OutOfMemoryError : Error {
constructor() : super() {
}
constructor(s: String) : super(s) {
}
}
@@ -8,20 +8,15 @@ public abstract class AbstractList<out E> protected constructor() : AbstractColl
abstract override val size: Int abstract override val size: Int
abstract override fun get(index: Int): E abstract override fun get(index: Int): E
// TODO: fix once have inner classes. override fun iterator(): Iterator<E> = IteratorImpl()
@FixmeInner
override fun iterator(): Iterator<E> = TODO() // IteratorImpl()
override fun indexOf(element: @UnsafeVariance E): Int = indexOfFirst { it == element } override fun indexOf(element: @UnsafeVariance E): Int = indexOfFirst { it == element }
override fun lastIndexOf(element: @UnsafeVariance E): Int = indexOfLast { it == element } override fun lastIndexOf(element: @UnsafeVariance E): Int = indexOfLast { it == element }
// TODO: fix once have inner classes. override fun listIterator(): ListIterator<E> = ListIteratorImpl(0)
@FixmeInner
override fun listIterator(): ListIterator<E> = TODO() // ListIteratorImpl(0)
@FixmeInner override fun listIterator(index: Int): ListIterator<E> = ListIteratorImpl(index)
override fun listIterator(index: Int): ListIterator<E> = TODO() // ListIteratorImpl(index)
override fun subList(fromIndex: Int, toIndex: Int): List<E> = SubList(this, fromIndex, toIndex) override fun subList(fromIndex: Int, toIndex: Int): List<E> = SubList(this, fromIndex, toIndex)
@@ -52,8 +47,7 @@ public abstract class AbstractList<out E> protected constructor() : AbstractColl
override fun hashCode(): Int = orderedHashCode(this) override fun hashCode(): Int = orderedHashCode(this)
// TODO: enable, once have inner classes.
/*
private open inner class IteratorImpl : Iterator<E> { private open inner class IteratorImpl : Iterator<E> {
/** the index of the item that will be returned on the next call to [next]`()` */ /** the index of the item that will be returned on the next call to [next]`()` */
protected var index = 0 protected var index = 0
@@ -86,7 +80,7 @@ public abstract class AbstractList<out E> protected constructor() : AbstractColl
} }
override fun previousIndex(): Int = index - 1 override fun previousIndex(): Int = index - 1
} */ }
internal companion object { internal companion object {
internal fun checkElementIndex(index: Int, size: Int) { internal fun checkElementIndex(index: Int, size: Int) {
@@ -1,11 +1,11 @@
package kotlin.collections package kotlin.collections
/*
private open class ReversedListReadOnly<out T>(private val delegate: List<T>) : AbstractList<T>() { private open class ReversedListReadOnly<out T>(private val delegate: List<T>) : AbstractList<T>() {
override val size: Int get() = delegate.size override val size: Int get() = delegate.size
override fun get(index: Int): T = delegate[reverseElementIndex(index)] override fun get(index: Int): T = delegate[reverseElementIndex(index)]
} }
/*
private class ReversedList<T>(private val delegate: MutableList<T>) : AbstractMutableList<T>() { private class ReversedList<T>(private val delegate: MutableList<T>) : AbstractMutableList<T>() {
override val size: Int get() = delegate.size override val size: Int get() = delegate.size
override fun get(index: Int): T = delegate[reverseElementIndex(index)] override fun get(index: Int): T = delegate[reverseElementIndex(index)]
@@ -17,7 +17,7 @@ private class ReversedList<T>(private val delegate: MutableList<T>) : AbstractMu
override fun add(index: Int, element: T) { override fun add(index: Int, element: T) {
delegate.add(reversePositionIndex(index), element) delegate.add(reversePositionIndex(index), element)
} }
} }*/
private fun List<*>.reverseElementIndex(index: Int) = // TODO: Use AbstractList.checkElementIndex: run { AbstractList.checkElementIndex(index, size); lastIndex - index } private fun List<*>.reverseElementIndex(index: Int) = // TODO: Use AbstractList.checkElementIndex: run { AbstractList.checkElementIndex(index, size); lastIndex - index }
if (index in 0..size - 1) size - index - 1 else throw IndexOutOfBoundsException("Index $index should be in range [${0..size - 1}].") if (index in 0..size - 1) size - index - 1 else throw IndexOutOfBoundsException("Index $index should be in range [${0..size - 1}].")
@@ -30,7 +30,7 @@ private fun List<*>.reversePositionIndex(index: Int) =
* All changes made in the original list will be reflected in the reversed one. * All changes made in the original list will be reflected in the reversed one.
*/ */
public fun <T> List<T>.asReversed(): List<T> = ReversedListReadOnly(this) public fun <T> List<T>.asReversed(): List<T> = ReversedListReadOnly(this)
/*
/** /**
* Returns a reversed mutable view of the original mutable List. * Returns a reversed mutable view of the original mutable List.
* All changes made in the original list will be reflected in the reversed one and vice versa. * All changes made in the original list will be reflected in the reversed one and vice versa.