Merge branch 'master' into inline
This commit is contained in:
@@ -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
|
||||||
|
}
|
||||||
+89
-22
@@ -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;")
|
||||||
|
|||||||
+40
-22
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
+40
-29
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+82
-43
@@ -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
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -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) {
|
||||||
|
|||||||
+105
@@ -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)
|
||||||
+3
@@ -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)
|
||||||
|
|
||||||
|
|||||||
+2
@@ -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>
|
||||||
|
|||||||
+3
-3
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -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"),
|
||||||
|
|||||||
+1
-1
@@ -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")
|
||||||
|
|||||||
+5
-1
@@ -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) =
|
||||||
|
|||||||
+2
@@ -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 {
|
||||||
|
|||||||
+3
-1
@@ -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
|
||||||
}!!
|
}!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+24
-17
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
@@ -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>()
|
||||||
|
|||||||
+10
-2
@@ -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)
|
||||||
|
|||||||
+2
-2
@@ -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")
|
||||||
}
|
}
|
||||||
|
|||||||
+201
@@ -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)!!
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -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()
|
||||||
@@ -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())
|
||||||
|
}
|
||||||
backend.native/tests/external/codegen/blackbox/innerNested/superConstructorCall/innerExtendsOuter.kt
Vendored
+1
-1
@@ -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()
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user