Simplify interop stubs and runtime. (#2627)

This commit is contained in:
Nikolay Igotti
2019-02-12 12:33:45 +03:00
committed by GitHub
parent 550163cc7b
commit 072f0fb9c4
17 changed files with 336 additions and 257 deletions
@@ -68,33 +68,30 @@ internal object nativeMemUtils {
} }
fun getByteArray(source: NativePointed, dest: ByteArray, length: Int) { fun getByteArray(source: NativePointed, dest: ByteArray, length: Int) {
val clazz = ByteArray::class.java unsafe.copyMemory(null, source.address, dest, byteArrayBaseOffset, length.toLong())
val baseOffset = unsafe.arrayBaseOffset(clazz).toLong();
unsafe.copyMemory(null, source.address, dest, baseOffset, length.toLong())
} }
fun putByteArray(source: ByteArray, dest: NativePointed, length: Int) { fun putByteArray(source: ByteArray, dest: NativePointed, length: Int) {
val clazz = ByteArray::class.java unsafe.copyMemory(source, byteArrayBaseOffset, null, dest.address, length.toLong())
val baseOffset = unsafe.arrayBaseOffset(clazz).toLong();
unsafe.copyMemory(source, baseOffset, null, dest.address, length.toLong())
} }
fun getCharArray(source: NativePointed, dest: CharArray, length: Int) { fun getCharArray(source: NativePointed, dest: CharArray, length: Int) {
val clazz = CharArray::class.java unsafe.copyMemory(null, source.address, dest, charArrayBaseOffset, length.toLong() * 2)
val baseOffset = unsafe.arrayBaseOffset(clazz).toLong();
unsafe.copyMemory(null, source.address, dest, baseOffset, length.toLong() * 2)
} }
fun putCharArray(source: CharArray, dest: NativePointed, length: Int) { fun putCharArray(source: CharArray, dest: NativePointed, length: Int) {
val clazz = CharArray::class.java unsafe.copyMemory(source, charArrayBaseOffset, null, dest.address, length.toLong() * 2)
val baseOffset = unsafe.arrayBaseOffset(clazz).toLong();
unsafe.copyMemory(source, baseOffset, null, dest.address, length.toLong() * 2)
} }
fun zeroMemory(dest: NativePointed, length: Int): Unit = unsafe.setMemory(dest.address, length.toLong(), 0) fun zeroMemory(dest: NativePointed, length: Int): Unit =
unsafe.setMemory(dest.address, length.toLong(), 0)
fun copyMemory(dest: NativePointed, length: Int, src: NativePointed) =
unsafe.copyMemory(src.address, dest.address, length.toLong())
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
inline fun<reified T> allocateInstance(): T { inline fun <reified T> allocateInstance(): T {
return unsafe.allocateInstance(T::class.java) as T return unsafe.allocateInstance(T::class.java) as T
} }
@@ -115,4 +112,7 @@ internal object nativeMemUtils {
isAccessible = true isAccessible = true
return@with this.get(null) as Unsafe return@with this.get(null) as Unsafe
} }
private val byteArrayBaseOffset = unsafe.arrayBaseOffset(ByteArray::class.java).toLong()
private val charArrayBaseOffset = unsafe.arrayBaseOffset(CharArray::class.java).toLong()
} }
@@ -23,7 +23,8 @@ typealias NativePtr = Long
internal typealias NonNullNativePtr = NativePtr internal typealias NonNullNativePtr = NativePtr
@PublishedApi internal fun NonNullNativePtr.toNativePtr() = this @PublishedApi internal fun NonNullNativePtr.toNativePtr() = this
internal fun NativePtr.toNonNull(): NonNullNativePtr = this internal fun NativePtr.toNonNull(): NonNullNativePtr = this
val nativeNullPtr: NativePtr = 0L
public val nativeNullPtr: NativePtr = 0L
// TODO: the functions below should eventually be intrinsified // TODO: the functions below should eventually be intrinsified
@@ -82,4 +82,4 @@ inline fun <reified R : Number> Long.narrow(): R = when (R::class.java) {
inline fun <reified R : Number> Number.invalidNarrowing(): R { inline fun <reified R : Number> Number.invalidNarrowing(): R {
throw Error("unable to narrow ${this.javaClass.simpleName} \"${this}\" to ${R::class.java.simpleName}") throw Error("unable to narrow ${this.javaClass.simpleName} \"${this}\" to ${R::class.java.simpleName}")
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2010-2019 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,13 +24,13 @@ package kotlinx.cinterop
* *
* TODO: the behavior of [equals], [hashCode] and [toString] differs on Native and JVM backends. * TODO: the behavior of [equals], [hashCode] and [toString] differs on Native and JVM backends.
*/ */
open class NativePointed internal constructor(rawPtr: NonNullNativePtr) { public open class NativePointed internal constructor(rawPtr: NonNullNativePtr) {
var rawPtr = rawPtr.toNativePtr() var rawPtr = rawPtr.toNativePtr()
internal set internal set
} }
// `null` value of `NativePointed?` is mapped to `nativeNullPtr`. // `null` value of `NativePointed?` is mapped to `nativeNullPtr`.
val NativePointed?.rawPtr: NativePtr public val NativePointed?.rawPtr: NativePtr
get() = if (this != null) this.rawPtr else nativeNullPtr get() = if (this != null) this.rawPtr else nativeNullPtr
/** /**
@@ -38,22 +38,22 @@ val NativePointed?.rawPtr: NativePtr
* *
* @param T must not be abstract * @param T must not be abstract
*/ */
inline fun <reified T : NativePointed> interpretPointed(ptr: NativePtr): T = interpretNullablePointed<T>(ptr)!! public inline fun <reified T : NativePointed> interpretPointed(ptr: NativePtr): T = interpretNullablePointed<T>(ptr)!!
private class OpaqueNativePointed(rawPtr: NativePtr) : NativePointed(rawPtr.toNonNull()) private class OpaqueNativePointed(rawPtr: NativePtr) : NativePointed(rawPtr.toNonNull())
fun interpretOpaquePointed(ptr: NativePtr): NativePointed = interpretPointed<OpaqueNativePointed>(ptr) public fun interpretOpaquePointed(ptr: NativePtr): NativePointed = interpretPointed<OpaqueNativePointed>(ptr)
fun interpretNullableOpaquePointed(ptr: NativePtr): NativePointed? = interpretNullablePointed<OpaqueNativePointed>(ptr) public fun interpretNullableOpaquePointed(ptr: NativePtr): NativePointed? = interpretNullablePointed<OpaqueNativePointed>(ptr)
/** /**
* Changes the interpretation of the pointed data or code. * Changes the interpretation of the pointed data or code.
*/ */
inline fun <reified T : NativePointed> NativePointed.reinterpret(): T = interpretPointed(this.rawPtr) public inline fun <reified T : NativePointed> NativePointed.reinterpret(): T = interpretPointed(this.rawPtr)
/** /**
* C data or code. * C data or code.
*/ */
abstract class CPointed(rawPtr: NativePtr) : NativePointed(rawPtr.toNonNull()) public abstract class CPointed(rawPtr: NativePtr) : NativePointed(rawPtr.toNonNull())
/** /**
* Represents a reference to (possibly empty) sequence of C values. * Represents a reference to (possibly empty) sequence of C values.
@@ -67,26 +67,28 @@ abstract class CPointed(rawPtr: NativePtr) : NativePointed(rawPtr.toNonNull())
* There are also other implementations of [CValuesRef] that provide temporary pointer, * There are also other implementations of [CValuesRef] that provide temporary pointer,
* e.g. Kotlin Native specific [refTo] functions to pass primitive arrays directly to native. * e.g. Kotlin Native specific [refTo] functions to pass primitive arrays directly to native.
*/ */
abstract class CValuesRef<T : CPointed> { public abstract class CValuesRef<T : CPointed> {
/** /**
* If this reference is [CPointer], returns this pointer. * If this reference is [CPointer], returns this pointer, otherwise
* Otherwise copies the referenced values to [placement] and returns the pointer to the copy. * allocate storage value in the scope and return it.
*/ */
abstract fun getPointer(scope: AutofreeScope): CPointer<T> public abstract fun getPointer(scope: AutofreeScope): CPointer<T>
} }
/** /**
* The (possibly empty) sequence of immutable C values. * The (possibly empty) sequence of immutable C values.
* It is self-contained and doesn't depend on native memory. * It is self-contained and doesn't depend on native memory.
*/ */
abstract class CValues<T : CVariable> : CValuesRef<T>() { public abstract class CValues<T : CVariable> : CValuesRef<T>() {
/** /**
* Copies the values to [placement] and returns the pointer to the copy. * Copies the values to [placement] and returns the pointer to the copy.
*/ */
abstract override fun getPointer(scope: AutofreeScope): CPointer<T> public override fun getPointer(scope: AutofreeScope): CPointer<T> {
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
}
// TODO: optimize // TODO: optimize
override fun equals(other: Any?): Boolean { public override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is CValues<*>) return false if (other !is CValues<*>) return false
@@ -106,7 +108,7 @@ abstract class CValues<T : CVariable> : CValuesRef<T>() {
return true return true
} }
override fun hashCode(): Int { public override fun hashCode(): Int {
var result = 0 var result = 0
for (byte in this.getBytes()) { for (byte in this.getBytes()) {
result = result * 31 + byte result = result * 31 + byte
@@ -114,10 +116,17 @@ abstract class CValues<T : CVariable> : CValuesRef<T>() {
return result return result
} }
abstract val size: Int public abstract val size: Int
public abstract val align: Int
/**
* Copy the referenced values to [placement] and return placement pointer.
*/
public abstract fun place(placement: CPointer<T>): CPointer<T>
} }
fun <T : CVariable> CValues<T>.placeTo(scope: AutofreeScope) = this.getPointer(scope) public fun <T : CVariable> CValues<T>.placeTo(scope: AutofreeScope) = this.getPointer(scope)
/** /**
* The single immutable C value. * The single immutable C value.
@@ -125,18 +134,18 @@ fun <T : CVariable> CValues<T>.placeTo(scope: AutofreeScope) = this.getPointer(s
* *
* TODO: consider providing an adapter instead of subtyping [CValues]. * TODO: consider providing an adapter instead of subtyping [CValues].
*/ */
abstract class CValue<T : CVariable> : CValues<T>() public abstract class CValue<T : CVariable> : CValues<T>()
/** /**
* C pointer. * C pointer.
*/ */
class CPointer<T : CPointed> internal constructor(@PublishedApi internal val value: NonNullNativePtr) : CValuesRef<T>() { public class CPointer<T : CPointed> internal constructor(@PublishedApi internal val value: NonNullNativePtr) : CValuesRef<T>() {
// TODO: replace by [value]. // TODO: replace by [value].
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline val rawValue: NativePtr get() = value.toNativePtr() public inline val rawValue: NativePtr get() = value.toNativePtr()
override fun equals(other: Any?): Boolean { public override fun equals(other: Any?): Boolean {
if (this === other) { if (this === other) {
return true // fast path return true // fast path
} }
@@ -144,19 +153,19 @@ class CPointer<T : CPointed> internal constructor(@PublishedApi internal val val
return (other is CPointer<*>) && (rawValue == other.rawValue) return (other is CPointer<*>) && (rawValue == other.rawValue)
} }
override fun hashCode(): Int { public override fun hashCode(): Int {
return rawValue.hashCode() return rawValue.hashCode()
} }
override fun toString() = this.cPointerToString() public override fun toString() = this.cPointerToString()
override fun getPointer(scope: AutofreeScope) = this public override fun getPointer(scope: AutofreeScope) = this
} }
/** /**
* Returns the pointer to this data or code. * Returns the pointer to this data or code.
*/ */
val <T : CPointed> T.ptr: CPointer<T> public val <T : CPointed> T.ptr: CPointer<T>
get() = interpretCPointer(this.rawPtr)!! get() = interpretCPointer(this.rawPtr)!!
/** /**
@@ -164,33 +173,33 @@ val <T : CPointed> T.ptr: CPointer<T>
* *
* @param T must not be abstract * @param T must not be abstract
*/ */
inline val <reified T : CPointed> CPointer<T>.pointed: T public inline val <reified T : CPointed> CPointer<T>.pointed: T
get() = interpretPointed<T>(this.rawValue) get() = interpretPointed<T>(this.rawValue)
// `null` value of `CPointer?` is mapped to `nativeNullPtr` // `null` value of `CPointer?` is mapped to `nativeNullPtr`
val CPointer<*>?.rawValue: NativePtr public val CPointer<*>?.rawValue: NativePtr
get() = if (this != null) this.rawValue else nativeNullPtr get() = if (this != null) this.rawValue else nativeNullPtr
fun <T : CPointed> CPointer<*>.reinterpret(): CPointer<T> = interpretCPointer(this.rawValue)!! public fun <T : CPointed> CPointer<*>.reinterpret(): CPointer<T> = interpretCPointer(this.rawValue)!!
fun <T : CPointed> CPointer<T>?.toLong() = this.rawValue.toLong() public fun <T : CPointed> CPointer<T>?.toLong() = this.rawValue.toLong()
fun <T : CPointed> Long.toCPointer(): CPointer<T>? = interpretCPointer(nativeNullPtr + this) public fun <T : CPointed> Long.toCPointer(): CPointer<T>? = interpretCPointer(nativeNullPtr + this)
/** /**
* The [CPointed] without any specified interpretation. * The [CPointed] without any specified interpretation.
*/ */
abstract class COpaque(rawPtr: NativePtr) : CPointed(rawPtr) // TODO: should it correspond to COpaquePointer? public abstract class COpaque(rawPtr: NativePtr) : CPointed(rawPtr) // TODO: should it correspond to COpaquePointer?
/** /**
* The pointer with an opaque type. * The pointer with an opaque type.
*/ */
typealias COpaquePointer = CPointer<out CPointed> // FIXME public typealias COpaquePointer = CPointer<out CPointed> // FIXME
/** /**
* The variable containing a [COpaquePointer]. * The variable containing a [COpaquePointer].
*/ */
typealias COpaquePointerVar = CPointerVarOf<COpaquePointer> public typealias COpaquePointerVar = CPointerVarOf<COpaquePointer>
/** /**
* The C data variable located in memory. * The C data variable located in memory.
@@ -198,7 +207,7 @@ typealias COpaquePointerVar = CPointerVarOf<COpaquePointer>
* The non-abstract subclasses should represent the (complete) C data type and thus specify size and alignment. * The non-abstract subclasses should represent the (complete) C data type and thus specify size and alignment.
* Each such subclass must have a companion object which is a [Type]. * Each such subclass must have a companion object which is a [Type].
*/ */
abstract class CVariable(rawPtr: NativePtr) : CPointed(rawPtr) { public abstract class CVariable(rawPtr: NativePtr) : CPointed(rawPtr) {
/** /**
* The (complete) C data type. * The (complete) C data type.
@@ -207,7 +216,7 @@ abstract class CVariable(rawPtr: NativePtr) : CPointed(rawPtr) {
* @param align the alignments in bytes that is enough for this data type. * @param align the alignments in bytes that is enough for this data type.
* It may be greater than actually required for simplicity. * It may be greater than actually required for simplicity.
*/ */
open class Type(val size: Long, val align: Int) { public open class Type(val size: Long, val align: Int) {
init { init {
require(size % align == 0L) require(size % align == 0L)
@@ -216,24 +225,24 @@ abstract class CVariable(rawPtr: NativePtr) : CPointed(rawPtr) {
} }
} }
inline fun <reified T : CVariable> sizeOf() = typeOf<T>().size public inline fun <reified T : CVariable> sizeOf() = typeOf<T>().size
inline fun <reified T : CVariable> alignOf() = typeOf<T>().align public inline fun <reified T : CVariable> alignOf() = typeOf<T>().align
/** /**
* Returns the member of this [CStructVar] which is located by given offset in bytes. * Returns the member of this [CStructVar] which is located by given offset in bytes.
*/ */
inline fun <reified T : CPointed> CStructVar.memberAt(offset: Long): T { public inline fun <reified T : CPointed> CStructVar.memberAt(offset: Long): T {
return interpretPointed<T>(this.rawPtr + offset) return interpretPointed<T>(this.rawPtr + offset)
} }
inline fun <reified T : CVariable> CStructVar.arrayMemberAt(offset: Long): CArrayPointer<T> { public inline fun <reified T : CVariable> CStructVar.arrayMemberAt(offset: Long): CArrayPointer<T> {
return interpretCPointer<T>(this.rawPtr + offset)!! return interpretCPointer<T>(this.rawPtr + offset)!!
} }
/** /**
* The C struct-typed variable located in memory. * The C struct-typed variable located in memory.
*/ */
abstract class CStructVar(rawPtr: NativePtr) : CVariable(rawPtr) { public abstract class CStructVar(rawPtr: NativePtr) : CVariable(rawPtr) {
open class Type(size: Long, align: Int) : CVariable.Type(size, align) open class Type(size: Long, align: Int) : CVariable.Type(size, align)
} }
@@ -245,83 +254,84 @@ sealed class CPrimitiveVar(rawPtr: NativePtr) : CVariable(rawPtr) {
open class Type(size: Int) : CVariable.Type(size.toLong(), align = size) open class Type(size: Int) : CVariable.Type(size.toLong(), align = size)
} }
interface CEnum { public interface CEnum {
val value: Any public val value: Any
} }
abstract class CEnumVar(rawPtr: NativePtr) : CPrimitiveVar(rawPtr)
public abstract class CEnumVar(rawPtr: NativePtr) : CPrimitiveVar(rawPtr)
// generics below are used for typedef support // generics below are used for typedef support
// these classes are not supposed to be used directly, instead the typealiases are provided. // these classes are not supposed to be used directly, instead the typealiases are provided.
@Suppress("FINAL_UPPER_BOUND") @Suppress("FINAL_UPPER_BOUND")
class BooleanVarOf<T : Boolean>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { public class BooleanVarOf<T : Boolean>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(1) companion object : Type(1)
} }
@Suppress("FINAL_UPPER_BOUND") @Suppress("FINAL_UPPER_BOUND")
class ByteVarOf<T : Byte>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { public class ByteVarOf<T : Byte>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(1) companion object : Type(1)
} }
@Suppress("FINAL_UPPER_BOUND") @Suppress("FINAL_UPPER_BOUND")
class ShortVarOf<T : Short>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { public class ShortVarOf<T : Short>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(2) companion object : Type(2)
} }
@Suppress("FINAL_UPPER_BOUND") @Suppress("FINAL_UPPER_BOUND")
class IntVarOf<T : Int>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { public class IntVarOf<T : Int>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(4) companion object : Type(4)
} }
@Suppress("FINAL_UPPER_BOUND") @Suppress("FINAL_UPPER_BOUND")
class LongVarOf<T : Long>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { public class LongVarOf<T : Long>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(8) companion object : Type(8)
} }
@Suppress("FINAL_UPPER_BOUND") @Suppress("FINAL_UPPER_BOUND")
class UByteVarOf<T : UByte>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { public class UByteVarOf<T : UByte>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(1) companion object : Type(1)
} }
@Suppress("FINAL_UPPER_BOUND") @Suppress("FINAL_UPPER_BOUND")
class UShortVarOf<T : UShort>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { public class UShortVarOf<T : UShort>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(2) companion object : Type(2)
} }
@Suppress("FINAL_UPPER_BOUND") @Suppress("FINAL_UPPER_BOUND")
class UIntVarOf<T : UInt>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { public class UIntVarOf<T : UInt>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(4) companion object : Type(4)
} }
@Suppress("FINAL_UPPER_BOUND") @Suppress("FINAL_UPPER_BOUND")
class ULongVarOf<T : ULong>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { public class ULongVarOf<T : ULong>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(8) companion object : Type(8)
} }
@Suppress("FINAL_UPPER_BOUND") @Suppress("FINAL_UPPER_BOUND")
class FloatVarOf<T : Float>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { public class FloatVarOf<T : Float>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(4) companion object : Type(4)
} }
@Suppress("FINAL_UPPER_BOUND") @Suppress("FINAL_UPPER_BOUND")
class DoubleVarOf<T : Double>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { public class DoubleVarOf<T : Double>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(8) companion object : Type(8)
} }
typealias BooleanVar = BooleanVarOf<Boolean> public typealias BooleanVar = BooleanVarOf<Boolean>
typealias ByteVar = ByteVarOf<Byte> public typealias ByteVar = ByteVarOf<Byte>
typealias ShortVar = ShortVarOf<Short> public typealias ShortVar = ShortVarOf<Short>
typealias IntVar = IntVarOf<Int> public typealias IntVar = IntVarOf<Int>
typealias LongVar = LongVarOf<Long> public typealias LongVar = LongVarOf<Long>
typealias UByteVar = UByteVarOf<UByte> public typealias UByteVar = UByteVarOf<UByte>
typealias UShortVar = UShortVarOf<UShort> public typealias UShortVar = UShortVarOf<UShort>
typealias UIntVar = UIntVarOf<UInt> public typealias UIntVar = UIntVarOf<UInt>
typealias ULongVar = ULongVarOf<ULong> public typealias ULongVar = ULongVarOf<ULong>
typealias FloatVar = FloatVarOf<Float> public typealias FloatVar = FloatVarOf<Float>
typealias DoubleVar = DoubleVarOf<Double> public typealias DoubleVar = DoubleVarOf<Double>
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : Boolean> BooleanVarOf<T>.value: T public var <T : Boolean> BooleanVarOf<T>.value: T
get() { get() {
val byte = nativeMemUtils.getByte(this) val byte = nativeMemUtils.getByte(this)
return byte.toBoolean() as T return byte.toBoolean() as T
@@ -329,78 +339,78 @@ var <T : Boolean> BooleanVarOf<T>.value: T
set(value) = nativeMemUtils.putByte(this, value.toByte()) set(value) = nativeMemUtils.putByte(this, value.toByte())
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun Boolean.toByte(): Byte = if (this) 1 else 0 public inline fun Boolean.toByte(): Byte = if (this) 1 else 0
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun Byte.toBoolean() = (this - 0 != 0) public inline fun Byte.toBoolean() = (this.toInt() != 0)
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : Byte> ByteVarOf<T>.value: T public var <T : Byte> ByteVarOf<T>.value: T
get() = nativeMemUtils.getByte(this) as T get() = nativeMemUtils.getByte(this) as T
set(value) = nativeMemUtils.putByte(this, value) set(value) = nativeMemUtils.putByte(this, value)
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : Short> ShortVarOf<T>.value: T public var <T : Short> ShortVarOf<T>.value: T
get() = nativeMemUtils.getShort(this) as T get() = nativeMemUtils.getShort(this) as T
set(value) = nativeMemUtils.putShort(this, value) set(value) = nativeMemUtils.putShort(this, value)
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : Int> IntVarOf<T>.value: T public var <T : Int> IntVarOf<T>.value: T
get() = nativeMemUtils.getInt(this) as T get() = nativeMemUtils.getInt(this) as T
set(value) = nativeMemUtils.putInt(this, value) set(value) = nativeMemUtils.putInt(this, value)
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : Long> LongVarOf<T>.value: T public var <T : Long> LongVarOf<T>.value: T
get() = nativeMemUtils.getLong(this) as T get() = nativeMemUtils.getLong(this) as T
set(value) = nativeMemUtils.putLong(this, value) set(value) = nativeMemUtils.putLong(this, value)
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : UByte> UByteVarOf<T>.value: T public var <T : UByte> UByteVarOf<T>.value: T
get() = nativeMemUtils.getByte(this).toUByte() as T get() = nativeMemUtils.getByte(this).toUByte() as T
set(value) = nativeMemUtils.putByte(this, value.toByte()) set(value) = nativeMemUtils.putByte(this, value.toByte())
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : UShort> UShortVarOf<T>.value: T public var <T : UShort> UShortVarOf<T>.value: T
get() = nativeMemUtils.getShort(this).toUShort() as T get() = nativeMemUtils.getShort(this).toUShort() as T
set(value) = nativeMemUtils.putShort(this, value.toShort()) set(value) = nativeMemUtils.putShort(this, value.toShort())
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : UInt> UIntVarOf<T>.value: T public var <T : UInt> UIntVarOf<T>.value: T
get() = nativeMemUtils.getInt(this).toUInt() as T get() = nativeMemUtils.getInt(this).toUInt() as T
set(value) = nativeMemUtils.putInt(this, value.toInt()) set(value) = nativeMemUtils.putInt(this, value.toInt())
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : ULong> ULongVarOf<T>.value: T public var <T : ULong> ULongVarOf<T>.value: T
get() = nativeMemUtils.getLong(this).toULong() as T get() = nativeMemUtils.getLong(this).toULong() as T
set(value) = nativeMemUtils.putLong(this, value.toLong()) set(value) = nativeMemUtils.putLong(this, value.toLong())
// TODO: ensure native floats have the appropriate binary representation // TODO: ensure native floats have the appropriate binary representation
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : Float> FloatVarOf<T>.value: T public var <T : Float> FloatVarOf<T>.value: T
get() = nativeMemUtils.getFloat(this) as T get() = nativeMemUtils.getFloat(this) as T
set(value) = nativeMemUtils.putFloat(this, value) set(value) = nativeMemUtils.putFloat(this, value)
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : Double> DoubleVarOf<T>.value: T public var <T : Double> DoubleVarOf<T>.value: T
get() = nativeMemUtils.getDouble(this) as T get() = nativeMemUtils.getDouble(this) as T
set(value) = nativeMemUtils.putDouble(this, value) set(value) = nativeMemUtils.putDouble(this, value)
class CPointerVarOf<T : CPointer<*>>(rawPtr: NativePtr) : CVariable(rawPtr) { public class CPointerVarOf<T : CPointer<*>>(rawPtr: NativePtr) : CVariable(rawPtr) {
companion object : CVariable.Type(pointerSize.toLong(), pointerSize) companion object : CVariable.Type(pointerSize.toLong(), pointerSize)
} }
/** /**
* The C data variable containing the pointer to `T`. * The C data variable containing the pointer to `T`.
*/ */
typealias CPointerVar<T> = CPointerVarOf<CPointer<T>> public typealias CPointerVar<T> = CPointerVarOf<CPointer<T>>
/** /**
* The value of this variable. * The value of this variable.
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
inline var <P : CPointer<*>> CPointerVarOf<P>.value: P? public inline var <P : CPointer<*>> CPointerVarOf<P>.value: P?
get() = interpretCPointer<CPointed>(nativeMemUtils.getNativePtr(this)) as P? get() = interpretCPointer<CPointed>(nativeMemUtils.getNativePtr(this)) as P?
set(value) = nativeMemUtils.putNativePtr(this, value.rawValue) set(value) = nativeMemUtils.putNativePtr(this, value.rawValue)
@@ -409,13 +419,13 @@ inline var <P : CPointer<*>> CPointerVarOf<P>.value: P?
* *
* @param T must not be abstract * @param T must not be abstract
*/ */
inline var <reified T : CPointed, reified P : CPointer<T>> CPointerVarOf<P>.pointed: T? public inline var <reified T : CPointed, reified P : CPointer<T>> CPointerVarOf<P>.pointed: T?
get() = this.value?.pointed get() = this.value?.pointed
set(value) { set(value) {
this.value = value?.ptr as P? this.value = value?.ptr as P?
} }
inline operator fun <reified T : CVariable> CPointer<T>.get(index: Long): T { public inline operator fun <reified T : CVariable> CPointer<T>.get(index: Long): T {
val offset = if (index == 0L) { val offset = 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 {
@@ -424,40 +434,40 @@ inline operator fun <reified T : CVariable> CPointer<T>.get(index: Long): T {
return interpretPointed(this.rawValue + offset) return interpretPointed(this.rawValue + offset)
} }
inline operator fun <reified T : CVariable> CPointer<T>.get(index: Int): T = this.get(index.toLong()) public inline operator fun <reified T : CVariable> CPointer<T>.get(index: Int): T = this.get(index.toLong())
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
@JvmName("plus\$CPointer") @JvmName("plus\$CPointer")
inline operator fun <T : CPointerVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? = public inline operator fun <T : CPointerVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
interpretCPointer(this.rawValue + index * pointerSize) interpretCPointer(this.rawValue + index * pointerSize)
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
@JvmName("plus\$CPointer") @JvmName("plus\$CPointer")
inline operator fun <T : CPointerVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? = public inline operator fun <T : CPointerVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
this + index.toLong() this + index.toLong()
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline operator fun <T : CPointer<*>> CPointer<CPointerVarOf<T>>.get(index: Int): T? = public inline operator fun <T : CPointer<*>> CPointer<CPointerVarOf<T>>.get(index: Int): T? =
(this + index)!!.pointed.value (this + index)!!.pointed.value
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline operator fun <T : CPointer<*>> CPointer<CPointerVarOf<T>>.set(index: Int, value: T?) { public inline operator fun <T : CPointer<*>> CPointer<CPointerVarOf<T>>.set(index: Int, value: T?) {
(this + index)!!.pointed.value = value (this + index)!!.pointed.value = value
} }
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline operator fun <T : CPointer<*>> CPointer<CPointerVarOf<T>>.get(index: Long): T? = public inline operator fun <T : CPointer<*>> CPointer<CPointerVarOf<T>>.get(index: Long): T? =
(this + index)!!.pointed.value (this + index)!!.pointed.value
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline operator fun <T : CPointer<*>> CPointer<CPointerVarOf<T>>.set(index: Long, value: T?) { public inline operator fun <T : CPointer<*>> CPointer<CPointerVarOf<T>>.set(index: Long, value: T?) {
(this + index)!!.pointed.value = value (this + index)!!.pointed.value = value
} }
typealias CArrayPointer<T> = CPointer<T> public typealias CArrayPointer<T> = CPointer<T>
typealias CArrayPointerVar<T> = CPointerVar<T> public typealias CArrayPointerVar<T> = CPointerVar<T>
/** /**
* The C function. * The C function.
*/ */
class CFunction<T : Function<*>>(rawPtr: NativePtr) : CPointed(rawPtr) public class CFunction<T : Function<*>>(rawPtr: NativePtr) : CPointed(rawPtr)
@@ -16,21 +16,21 @@
package kotlinx.cinterop package kotlinx.cinterop
interface NativePlacement { public interface NativePlacement {
fun alloc(size: Long, align: Int): NativePointed public fun alloc(size: Long, align: Int): NativePointed
fun alloc(size: Int, align: Int) = alloc(size.toLong(), align) public fun alloc(size: Int, align: Int): NativePointed = alloc(size.toLong(), align)
} }
interface NativeFreeablePlacement : NativePlacement { public interface NativeFreeablePlacement : NativePlacement {
fun free(mem: NativePtr) public fun free(mem: NativePtr)
} }
fun NativeFreeablePlacement.free(pointer: CPointer<*>) = this.free(pointer.rawValue) public fun NativeFreeablePlacement.free(pointer: CPointer<*>) = this.free(pointer.rawValue)
fun NativeFreeablePlacement.free(pointed: NativePointed) = this.free(pointed.rawPtr) public fun NativeFreeablePlacement.free(pointed: NativePointed) = this.free(pointed.rawPtr)
object nativeHeap : NativeFreeablePlacement { public object nativeHeap : NativeFreeablePlacement {
override fun alloc(size: Long, align: Int) = nativeMemUtils.alloc(size, align) override fun alloc(size: Long, align: Int) = nativeMemUtils.alloc(size, align)
override fun free(mem: NativePtr) = nativeMemUtils.free(mem) override fun free(mem: NativePtr) = nativeMemUtils.free(mem)
@@ -38,7 +38,7 @@ object nativeHeap : NativeFreeablePlacement {
private typealias Deferred = () -> Unit private typealias Deferred = () -> Unit
open class DeferScope { public open class DeferScope {
@PublishedApi @PublishedApi
internal var topDeferred: Deferred? = null internal var topDeferred: Deferred? = null
@@ -65,11 +65,11 @@ open class DeferScope {
} }
} }
abstract class AutofreeScope : DeferScope(), NativePlacement { public abstract class AutofreeScope : DeferScope(), NativePlacement {
abstract override fun alloc(size: Long, align: Int): NativePointed abstract override fun alloc(size: Long, align: Int): NativePointed
} }
open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : AutofreeScope() { public open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : AutofreeScope() {
private var lastChunk: NativePointed? = null private var lastChunk: NativePointed? = null
@@ -97,7 +97,7 @@ open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) :
} }
class Arena(parent: NativeFreeablePlacement = nativeHeap) : ArenaBase(parent) { public class Arena(parent: NativeFreeablePlacement = nativeHeap) : ArenaBase(parent) {
fun clear() = this.clearImpl() fun clear() = this.clearImpl()
} }
@@ -106,7 +106,7 @@ class Arena(parent: NativeFreeablePlacement = nativeHeap) : ArenaBase(parent) {
* *
* @param T must not be abstract * @param T must not be abstract
*/ */
inline fun <reified T : CVariable> NativePlacement.alloc(): T = public inline fun <reified T : CVariable> NativePlacement.alloc(): T =
alloc(typeOf<T>()).reinterpret() alloc(typeOf<T>()).reinterpret()
@PublishedApi @PublishedApi
@@ -118,7 +118,7 @@ internal fun NativePlacement.alloc(type: CVariable.Type): NativePointed =
* *
* @param T must not be abstract * @param T must not be abstract
*/ */
inline fun <reified T : CVariable> NativePlacement.alloc(initialize: T.() -> Unit): T = public inline fun <reified T : CVariable> NativePlacement.alloc(initialize: T.() -> Unit): T =
alloc<T>().also { it.initialize() } alloc<T>().also { it.initialize() }
/** /**
@@ -126,7 +126,7 @@ inline fun <reified T : CVariable> NativePlacement.alloc(initialize: T.() -> Uni
* *
* @param T must not be abstract * @param T must not be abstract
*/ */
inline fun <reified T : CVariable> NativePlacement.allocArray(length: Long): CArrayPointer<T> = public inline fun <reified T : CVariable> NativePlacement.allocArray(length: Long): CArrayPointer<T> =
alloc(sizeOf<T>() * length, alignOf<T>()).reinterpret<T>().ptr alloc(sizeOf<T>() * length, alignOf<T>()).reinterpret<T>().ptr
/** /**
@@ -134,7 +134,7 @@ inline fun <reified T : CVariable> NativePlacement.allocArray(length: Long): CAr
* *
* @param T must not be abstract * @param T must not be abstract
*/ */
inline fun <reified T : CVariable> NativePlacement.allocArray(length: Int): CArrayPointer<T> = public inline fun <reified T : CVariable> NativePlacement.allocArray(length: Int): CArrayPointer<T> =
allocArray(length.toLong()) allocArray(length.toLong())
/** /**
@@ -142,7 +142,7 @@ inline fun <reified T : CVariable> NativePlacement.allocArray(length: Int): CArr
* *
* @param T must not be abstract * @param T must not be abstract
*/ */
inline fun <reified T : CVariable> NativePlacement.allocArray(length: Long, public inline fun <reified T : CVariable> NativePlacement.allocArray(length: Long,
initializer: T.(index: Long)->Unit): CArrayPointer<T> { initializer: T.(index: Long)->Unit): CArrayPointer<T> {
val res = allocArray<T>(length) val res = allocArray<T>(length)
@@ -158,9 +158,8 @@ inline fun <reified T : CVariable> NativePlacement.allocArray(length: Long,
* *
* @param T must not be abstract * @param T must not be abstract
*/ */
inline fun <reified T : CVariable> NativePlacement.allocArray(length: Int, public inline fun <reified T : CVariable> NativePlacement.allocArray(
initializer: T.(index: Int)->Unit): CArrayPointer<T> = length: Int, initializer: T.(index: Int)->Unit): CArrayPointer<T> = allocArray(length.toLong()) { index ->
allocArray(length.toLong()) { index ->
this.initializer(index.toInt()) this.initializer(index.toInt())
} }
@@ -168,7 +167,7 @@ inline fun <reified T : CVariable> NativePlacement.allocArray(length: Int,
/** /**
* Allocates C array of pointers to given elements. * Allocates C array of pointers to given elements.
*/ */
fun <T : CPointed> NativePlacement.allocArrayOfPointersTo(elements: List<T?>): CArrayPointer<CPointerVar<T>> { public fun <T : CPointed> NativePlacement.allocArrayOfPointersTo(elements: List<T?>): CArrayPointer<CPointerVar<T>> {
val res = allocArray<CPointerVar<T>>(elements.size) val res = allocArray<CPointerVar<T>>(elements.size)
elements.forEachIndexed { index, value -> elements.forEachIndexed { index, value ->
res[index] = value?.ptr res[index] = value?.ptr
@@ -179,22 +178,21 @@ 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?) = public fun <T : CPointed> NativePlacement.allocArrayOfPointersTo(vararg elements: T?) =
allocArrayOfPointersTo(listOf(*elements)) allocArrayOfPointersTo(listOf(*elements))
/** /**
* Allocates C array of given values. * Allocates C array of given values.
*/ */
inline fun <reified T : CPointer<*>> public inline fun <reified T : CPointer<*>>
NativePlacement.allocArrayOf(vararg elements: T?): CArrayPointer<CPointerVarOf<T>> { NativePlacement.allocArrayOf(vararg elements: T?): CArrayPointer<CPointerVarOf<T>> {
return allocArrayOf(listOf(*elements)) return allocArrayOf(listOf(*elements))
} }
/** /**
* Allocates C array of given values. * Allocates C array of given values.
*/ */
inline fun <reified T : CPointer<*>> public inline fun <reified T : CPointer<*>>
NativePlacement.allocArrayOf(elements: List<T?>): CArrayPointer<CPointerVarOf<T>> { NativePlacement.allocArrayOf(elements: List<T?>): CArrayPointer<CPointerVarOf<T>> {
val res = allocArray<CPointerVarOf<T>>(elements.size) val res = allocArray<CPointerVarOf<T>>(elements.size)
@@ -206,13 +204,13 @@ inline fun <reified T : CPointer<*>>
return res return res
} }
fun NativePlacement.allocArrayOf(elements: ByteArray): CArrayPointer<ByteVar> { public fun NativePlacement.allocArrayOf(elements: ByteArray): CArrayPointer<ByteVar> {
val result = allocArray<ByteVar>(elements.size) val result = allocArray<ByteVar>(elements.size)
nativeMemUtils.putByteArray(elements, result.pointed, elements.size) nativeMemUtils.putByteArray(elements, result.pointed, elements.size)
return result return result
} }
fun NativePlacement.allocArrayOf(vararg elements: Float): CArrayPointer<FloatVar> { public fun NativePlacement.allocArrayOf(vararg elements: Float): CArrayPointer<FloatVar> {
val res = allocArray<FloatVar>(elements.size) val res = allocArray<FloatVar>(elements.size)
var index = 0 var index = 0
while (index < elements.size) { while (index < elements.size) {
@@ -222,48 +220,67 @@ fun NativePlacement.allocArrayOf(vararg elements: Float): CArrayPointer<FloatVar
return res return res
} }
fun <T : CPointed> NativePlacement.allocPointerTo() = alloc<CPointerVar<T>>() public fun <T : CPointed> NativePlacement.allocPointerTo() = alloc<CPointerVar<T>>()
fun <T : CVariable> zeroValue(size: Int, align: Int): CValue<T> = object : CValue<T>() { @PublishedApi
internal class ZeroValue<T: CVariable>(private val sizeBytes: Int, private val alignBytes: Int): CValue<T>() {
// Optimization to avoid unneeded virtual calls in base class implementation.
override fun getPointer(scope: AutofreeScope): CPointer<T> { override fun getPointer(scope: AutofreeScope): CPointer<T> {
val result = scope.alloc(size, align) return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
nativeMemUtils.zeroMemory(result, size)
return interpretCPointer(result.rawPtr)!!
} }
override val size get() = size override fun place(placement: CPointer<T>): CPointer<T> {
nativeMemUtils.zeroMemory(interpretPointed(placement.rawValue), sizeBytes)
return placement
}
override val size get() = sizeBytes
override val align get() = alignBytes
} }
@Suppress("NOTHING_TO_INLINE")
public inline fun <T : CVariable> zeroValue(size: Int, align: Int): CValue<T> = ZeroValue(size, align)
inline fun <reified T : CVariable> zeroValue(): CValue<T> = public inline fun <reified T : CVariable> zeroValue(): CValue<T> = zeroValue<T>(sizeOf<T>().toInt(), alignOf<T>())
zeroValue<T>(sizeOf<T>().toInt(), alignOf<T>())
inline fun <reified T : CVariable> cValue(): CValue<T> = zeroValue<T>() public inline fun <reified T : CVariable> cValue(): CValue<T> = zeroValue<T>()
private fun <T : CPointed> NativePlacement.placeBytes(bytes: ByteArray, align: Int): CPointer<T> { public fun <T : CVariable> CPointed.readValues(size: Int, align: Int): CValues<T> {
val result = this.alloc(size = bytes.size, align = align)
nativeMemUtils.putByteArray(bytes, result, bytes.size)
return interpretCPointer(result.rawPtr)!!
}
fun <T : CVariable> CPointed.readValues(size: Int, align: Int): CValues<T> {
val bytes = ByteArray(size) val bytes = ByteArray(size)
nativeMemUtils.getByteArray(this, bytes, size) nativeMemUtils.getByteArray(this, bytes, size)
return object : CValues<T>() { return object : CValue<T>() {
override fun getPointer(scope: AutofreeScope): CPointer<T> = scope.placeBytes(bytes, align) // Optimization to avoid unneeded virtual calls in base class implementation.
override val size get() = bytes.size override fun getPointer(scope: AutofreeScope): CPointer<T> {
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
}
override fun place(placement: CPointer<T>): CPointer<T> {
nativeMemUtils.putByteArray(bytes, interpretPointed(placement.rawValue), bytes.size)
return placement
}
override val size get() = size
override val align get() = align
} }
} }
inline fun <reified T : CVariable> T.readValues(count: Int): CValues<T> = public inline fun <reified T : CVariable> T.readValues(count: Int): CValues<T> =
this.readValues<T>(size = count * sizeOf<T>().toInt(), align = alignOf<T>()) this.readValues<T>(size = count * sizeOf<T>().toInt(), align = alignOf<T>())
fun <T : CVariable> CPointed.readValue(size: Long, align: Int): CValue<T> { public fun <T : CVariable> CPointed.readValue(size: Long, align: Int): CValue<T> {
val bytes = ByteArray(size.toInt()) val bytes = ByteArray(size.toInt())
nativeMemUtils.getByteArray(this, bytes, size.toInt()) nativeMemUtils.getByteArray(this, bytes, size.toInt())
return object : CValue<T>() { return object : CValue<T>() {
override fun getPointer(scope: AutofreeScope): CPointer<T> = scope.placeBytes(bytes, align) override fun place(placement: CPointer<T>): CPointer<T> {
override val size get() = bytes.size nativeMemUtils.putByteArray(bytes, interpretPointed(placement.rawValue), bytes.size)
return placement
}
// Optimization to avoid unneeded virtual calls in base class implementation.
public override fun getPointer(scope: AutofreeScope): CPointer<T> {
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
}
override val size get() = size.toInt()
override val align get() = align
} }
} }
@@ -272,138 +289,140 @@ fun <T : CVariable> CPointed.readValue(size: Long, align: Int): CValue<T> {
// Note: can't be declared as property due to possible clash with a struct field. // Note: can't be declared as property due to possible clash with a struct field.
// TODO: find better name. // TODO: find better name.
inline fun <reified T : CStructVar> T.readValue(): CValue<T> = this.readValue(typeOf<T>()) public inline fun <reified T : CStructVar> T.readValue(): CValue<T> = this.readValue(typeOf<T>())
fun CValue<*>.write(location: NativePtr) { public fun <T: CVariable> CValue<T>.write(location: NativePtr) {
// TODO: probably CValue must be redesigned. this.place(interpretCPointer(location)!!)
val fakeScope = object : AutofreeScope() {
var used = false
override fun alloc(size: Long, align: Int): NativePointed {
assert(!used)
used = true
return interpretPointed<ByteVar>(location)
}
}
this.getPointer(fakeScope)
assert(fakeScope.used)
} }
// TODO: optimize // TODO: optimize
fun <T : CVariable> CValues<T>.getBytes(): ByteArray = memScoped { public fun <T : CVariable> CValues<T>.getBytes(): ByteArray = memScoped {
val result = ByteArray(size) val result = ByteArray(size)
nativeMemUtils.getByteArray( nativeMemUtils.getByteArray(
source = this@getBytes.placeTo(memScope).reinterpret<ByteVar>().pointed, source = this@getBytes.placeTo(memScope).reinterpret<ByteVar>().pointed,
dest = result, dest = result,
length = result.size length = result.size
) )
result result
} }
/** /**
* Calls the [block] with temporary copy if this value as receiver. * Calls the [block] with temporary copy if this value as receiver.
*/ */
inline fun <reified T : CStructVar, R> CValue<T>.useContents(block: T.() -> R): R = memScoped { public inline fun <reified T : CStructVar, R> CValue<T>.useContents(block: T.() -> R): R = memScoped {
this@useContents.placeTo(memScope).pointed.block() this@useContents.placeTo(memScope).pointed.block()
} }
inline fun <reified T : CStructVar> CValue<T>.copy(modify: T.() -> Unit): CValue<T> = useContents { public inline fun <reified T : CStructVar> CValue<T>.copy(modify: T.() -> Unit): CValue<T> = useContents {
this.modify() this.modify()
this.readValue() this.readValue()
} }
inline fun <reified T : CStructVar> cValue(initialize: T.() -> Unit): CValue<T> = public inline fun <reified T : CStructVar> cValue(initialize: T.() -> Unit): CValue<T> =
zeroValue<T>().copy(modify = initialize) zeroValue<T>().copy(modify = initialize)
inline fun <reified T : CVariable> createValues(count: Int, initializer: T.(index: Int) -> Unit) = memScoped { public inline fun <reified T : CVariable> createValues(count: Int, initializer: T.(index: Int) -> Unit) = memScoped {
val array = allocArray<T>(count, initializer) val array = allocArray<T>(count, initializer)
array[0].readValues(count) array[0].readValues(count)
} }
fun cValuesOf(vararg elements: Byte): CValues<ByteVar> = object : CValues<ByteVar>() {
override fun getPointer(scope: AutofreeScope) = scope.allocArrayOf(elements)
override val size get() = 1 * elements.size
}
// TODO: optimize other [cValuesOf] methods: // TODO: optimize other [cValuesOf] methods:
fun cValuesOf(vararg elements: Byte): CValues<ByteVar> = object : CValues<ByteVar>() {
// Optimization to avoid unneeded virtual calls in base class implementation.
override fun getPointer(scope: AutofreeScope): CPointer<ByteVar> {
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
}
override fun place(placement: CPointer<ByteVar>): CPointer<ByteVar> {
nativeMemUtils.putByteArray(elements, interpretPointed(placement.rawValue), elements.size)
return placement
}
fun cValuesOf(vararg elements: Short): CValues<ShortVar> = override val size get() = 1 * elements.size
createValues(elements.size) { index -> this.value = elements[index] } override val align get() = 1
fun cValuesOf(vararg elements: Int): CValues<IntVar> =
createValues(elements.size) { index -> this.value = elements[index] }
fun cValuesOf(vararg elements: Long): CValues<LongVar> =
createValues(elements.size) { index -> this.value = elements[index] }
fun cValuesOf(vararg elements: Float): CValues<FloatVar> = object : CValues<FloatVar>() {
override fun getPointer(scope: AutofreeScope) = scope.allocArrayOf(*elements)
override val size get() = 4 * elements.size
} }
fun cValuesOf(vararg elements: Double): CValues<DoubleVar> = public fun cValuesOf(vararg elements: Short): CValues<ShortVar> =
createValues(elements.size) { index -> this.value = elements[index] } createValues(elements.size) { index -> this.value = elements[index] }
fun <T : CPointed> cValuesOf(vararg elements: CPointer<T>?): CValues<CPointerVar<T>> = public fun cValuesOf(vararg elements: Int): CValues<IntVar> =
createValues(elements.size) { index -> this.value = elements[index] } createValues(elements.size) { index -> this.value = elements[index] }
fun ByteArray.toCValues() = cValuesOf(*this) public fun cValuesOf(vararg elements: Long): CValues<LongVar> =
fun ShortArray.toCValues() = cValuesOf(*this) createValues(elements.size) { index -> this.value = elements[index] }
fun IntArray.toCValues() = cValuesOf(*this)
fun LongArray.toCValues() = cValuesOf(*this)
fun FloatArray.toCValues() = cValuesOf(*this)
fun DoubleArray.toCValues() = cValuesOf(*this)
fun <T : CPointed> Array<CPointer<T>?>.toCValues() = cValuesOf(*this)
fun <T : CPointed> List<CPointer<T>?>.toCValues() = this.toTypedArray().toCValues() public fun cValuesOf(vararg elements: Float): CValues<FloatVar> =
createValues(elements.size) { index -> this.value = elements[index] }
public fun cValuesOf(vararg elements: Double): CValues<DoubleVar> =
createValues(elements.size) { index -> this.value = elements[index] }
public fun <T : CPointed> cValuesOf(vararg elements: CPointer<T>?): CValues<CPointerVar<T>> =
createValues(elements.size) { index -> this.value = elements[index] }
public fun ByteArray.toCValues() = cValuesOf(*this)
public fun ShortArray.toCValues() = cValuesOf(*this)
public fun IntArray.toCValues() = cValuesOf(*this)
public fun LongArray.toCValues() = cValuesOf(*this)
public fun FloatArray.toCValues() = cValuesOf(*this)
public fun DoubleArray.toCValues() = cValuesOf(*this)
public fun <T : CPointed> Array<CPointer<T>?>.toCValues() = cValuesOf(*this)
public fun <T : CPointed> List<CPointer<T>?>.toCValues() = this.toTypedArray().toCValues()
private class CString(val bytes: ByteArray): CValues<ByteVar>() { private class CString(val bytes: ByteArray): CValues<ByteVar>() {
override val size get() = bytes.size + 1 override val size get() = bytes.size + 1
override val align get() = 1
// Optimization to avoid unneeded virtual calls in base class implementation.
override fun getPointer(scope: AutofreeScope): CPointer<ByteVar> { override fun getPointer(scope: AutofreeScope): CPointer<ByteVar> {
val result = scope.allocArray<ByteVar>(bytes.size + 1) return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
nativeMemUtils.putByteArray(bytes, result.pointed, bytes.size) }
result[bytes.size] = 0.toByte() override fun place(placement: CPointer<ByteVar>): CPointer<ByteVar> {
return result nativeMemUtils.putByteArray(bytes, placement.pointed, bytes.size)
placement[bytes.size] = 0.toByte()
return placement
} }
} }
/** /**
* @return the value of zero-terminated UTF-8-encoded C string constructed from given [kotlin.String]. * @return the value of zero-terminated UTF-8-encoded C string constructed from given [kotlin.String].
*/ */
val String.cstr: CValues<ByteVar> public val String.cstr: CValues<ByteVar>
get() = CString(encodeToUtf8(this)) get() = CString(encodeToUtf8(this))
/** /**
* Convert this list of Kotlin strings to C array of C strings, * Convert this list of Kotlin strings to C array of C strings,
* allocating memory for the array and C strings with given [AutofreeScope]. * allocating memory for the array and C strings with given [AutofreeScope].
*/ */
fun List<String>.toCStringArray(autofreeScope: AutofreeScope): CPointer<CPointerVar<ByteVar>> = public fun List<String>.toCStringArray(autofreeScope: AutofreeScope): CPointer<CPointerVar<ByteVar>> =
autofreeScope.allocArrayOf(this.map { it.cstr.getPointer(autofreeScope) }) autofreeScope.allocArrayOf(this.map { it.cstr.getPointer(autofreeScope) })
/** /**
* Convert this array of Kotlin strings to C array of C strings, * Convert this array of Kotlin strings to C array of C strings,
* allocating memory for the array and C strings with given [AutofreeScope]. * allocating memory for the array and C strings with given [AutofreeScope].
*/ */
fun Array<String>.toCStringArray(autofreeScope: AutofreeScope): CPointer<CPointerVar<ByteVar>> = public fun Array<String>.toCStringArray(autofreeScope: AutofreeScope): CPointer<CPointerVar<ByteVar>> =
autofreeScope.allocArrayOf(this.map { it.cstr.getPointer(autofreeScope) }) autofreeScope.allocArrayOf(this.map { it.cstr.getPointer(autofreeScope) })
private class WCString(val chars: CharArray): CValues<UShortVar>() { private class WCString(val chars: CharArray): CValues<UShortVar>() {
override val size get() = 2 * (chars.size + 1) override val size get() = 2 * (chars.size + 1)
override val align get() = 2
// Optimization to avoid unneeded virtual calls in base class implementation.
override fun getPointer(scope: AutofreeScope): CPointer<UShortVar> { override fun getPointer(scope: AutofreeScope): CPointer<UShortVar> {
val result = scope.allocArray<UShortVar>(chars.size + 1) return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
nativeMemUtils.putCharArray(chars, result.pointed, chars.size) }
override fun place(placement: CPointer<UShortVar>): CPointer<UShortVar> {
nativeMemUtils.putCharArray(chars, placement.pointed, chars.size)
// TODO: fix, after KT-29627 is fixed. // TODO: fix, after KT-29627 is fixed.
nativeMemUtils.putShort((result + chars.size)!!.pointed, 0) nativeMemUtils.putShort((placement + chars.size)!!.pointed, 0)
return result return placement
} }
} }
val String.wcstr: CValues<UShortVar> public val String.wcstr: CValues<UShortVar>
get() = WCString(this.toCharArray()) get() = WCString(this.toCharArray())
/** /**
@@ -412,7 +431,7 @@ val String.wcstr: CValues<UShortVar>
* @return the [kotlin.String] decoded from given zero-terminated UTF-8-encoded C string. * @return the [kotlin.String] decoded from given zero-terminated UTF-8-encoded C string.
*/ */
// TODO: optimize // TODO: optimize
fun CPointer<ByteVar>.toKString(): String { public fun CPointer<ByteVar>.toKString(): String {
val nativeBytes = this val nativeBytes = this
var length = 0 var length = 0
@@ -425,7 +444,7 @@ fun CPointer<ByteVar>.toKString(): String {
return decodeFromUtf8(bytes) return decodeFromUtf8(bytes)
} }
class MemScope : ArenaBase() { public class MemScope : ArenaBase() {
val memScope: MemScope val memScope: MemScope
get() = this get() = this
@@ -440,7 +459,7 @@ class MemScope : ArenaBase() {
* Runs given [block] providing allocation of memory * Runs given [block] providing allocation of memory
* 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 { public inline fun <R> memScoped(block: MemScope.()->R): R {
val memScope = MemScope() val memScope = MemScope()
try { try {
return memScope.block() return memScope.block()
@@ -449,7 +468,7 @@ inline fun <R> memScoped(block: MemScope.()->R): R {
} }
} }
fun COpaquePointer.readBytes(count: Int): ByteArray { public fun COpaquePointer.readBytes(count: Int): ByteArray {
val result = ByteArray(count) val result = ByteArray(count)
nativeMemUtils.getByteArray(this.reinterpret<ByteVar>().pointed, result, count) nativeMemUtils.getByteArray(this.reinterpret<ByteVar>().pointed, result, count)
return result return result
@@ -103,6 +103,17 @@ internal object nativeMemUtils {
} }
} }
// TODO: optimize
fun copyMemory(dest: NativePointed, length: Int, src: NativePointed): Unit {
val destArray = dest.reinterpret<ByteVar>().ptr
val srcArray = src.reinterpret<ByteVar>().ptr
var index = 0
while (index < length) {
destArray[index] = srcArray[index]
++index
}
}
fun alloc(size: Long, align: Int): NativePointed { fun alloc(size: Long, align: Int): NativePointed {
val ptr = malloc(size, align) val ptr = malloc(size, align)
if (ptr == nativeNullPtr) { if (ptr == nativeNullPtr) {
@@ -157,4 +168,4 @@ private external fun cfree(ptr: NativePtr)
@TypedIntrinsic(IntrinsicType.INTEROP_READ_BITS) @TypedIntrinsic(IntrinsicType.INTEROP_READ_BITS)
external fun readBits(ptr: NativePtr, offset: Long, size: Int, signed: Boolean): Long external fun readBits(ptr: NativePtr, offset: Long, size: Int, signed: Boolean): Long
@TypedIntrinsic(IntrinsicType.INTEROP_WRITE_BITS) @TypedIntrinsic(IntrinsicType.INTEROP_WRITE_BITS)
external fun writeBits(ptr: NativePtr, offset: Long, size: Int, value: Long) external fun writeBits(ptr: NativePtr, offset: Long, size: Int, value: Long)
@@ -34,14 +34,25 @@ inline fun buildNativeCodeLines(scope: NativeScope, block: NativeCodeBuilder.()
return builder.lines return builder.lines
} }
class KotlinCodeBuilder(val scope: KotlinScope) { private class Block(val nesting: Int, val start: String, val end: String) {
private val lines = mutableListOf<String>() val prologue = mutableListOf<String>()
val body = mutableListOf<String>()
val epilogue = mutableListOf<String>()
private val freeStack = mutableListOf<String>() fun indent(line: String) = " ".repeat(nesting) + line
private val nesting get() = freeStack.size fun indentBraces(line: String) = " ".repeat(nesting - 1) + line
}
class KotlinCodeBuilder(val scope: KotlinScope) {
private val blocks = mutableListOf<Block>()
init {
pushBlock("", "")
}
fun out(line: String) { fun out(line: String) {
lines.add(" ".repeat(nesting) + line) currentBlock().body += line
} }
private var memScoped = false private var memScoped = false
@@ -52,24 +63,36 @@ class KotlinCodeBuilder(val scope: KotlinScope) {
} }
} }
fun pushBlock(line: String, free: String = "") { fun getNativePointer(name: String): String {
out(line) return "$name?.getPointer(memScope)"
freeStack.add(free)
} }
private fun popBlocks() { fun returnResult(result: String) {
while (freeStack.isNotEmpty()) { currentBlock().body += "return $result"
val free = freeStack.last() }
freeStack.removeAt(freeStack.lastIndex)
out("} $free".trim()) private fun currentBlock() = blocks.last()
}
fun pushBlock(start: String, end: String = "}") {
val block = Block(blocks.size, start = start, end = end)
blocks += block
}
private fun emitBlockAndNested(position: Int, lines: MutableList<String>) {
if (position >= blocks.size) return
val block = blocks[position]
if (block.start.isNotEmpty()) lines += block.indentBraces(block.start)
lines += block.prologue.map { block.indent(it) }
lines += block.body.map { block.indent(it) }
emitBlockAndNested(position + 1, lines)
lines += block.epilogue.map { block.indent(it) }
if (block.end.isNotEmpty()) lines += block.indentBraces(block.end)
} }
fun build(): List<String> { fun build(): List<String> {
this.popBlocks() val lines = mutableListOf<String>()
val result = this.lines.toList() emitBlockAndNested(0, lines)
this.lines.clear() return lines.toList()
return result
} }
} }
@@ -57,8 +57,9 @@ class MappingBridgeGeneratorImpl(
is RecordType -> { is RecordType -> {
val mirror = mirror(declarationMapper, returnType) val mirror = mirror(declarationMapper, returnType)
val tmpVarName = kniRetVal val tmpVarName = kniRetVal
// We clear in the finally block.
builder.out("val $tmpVarName = nativeHeap.alloc<${mirror.pointedType.render(builder.scope)}>()") builder.out("val $tmpVarName = nativeHeap.alloc<${mirror.pointedType.render(builder.scope)}>()")
builder.pushBlock("try {", free = "finally { nativeHeap.free($tmpVarName) }") builder.pushBlock(start = "try {", end = "} finally { nativeHeap.free($tmpVarName) }")
bridgeArguments.add(BridgeTypedKotlinValue(BridgedType.NATIVE_PTR, "$tmpVarName.rawPtr")) bridgeArguments.add(BridgeTypedKotlinValue(BridgedType.NATIVE_PTR, "$tmpVarName.rawPtr"))
BridgedType.VOID BridgedType.VOID
} }
@@ -315,7 +315,7 @@ sealed class TypeInfo {
val objCBlock = "((__bridge $blockType)${nativeValues.last()})" val objCBlock = "((__bridge $blockType)${nativeValues.last()})"
"$objCBlock(${nativeValues.dropLast(1).joinToString()})" "$objCBlock(${nativeValues.dropLast(1).joinToString()})"
}.let { }.let {
codeBuilder.out("return $it") codeBuilder.returnResult(it)
} }
codeBuilder.build().joinTo(this, separator = "\n") codeBuilder.build().joinTo(this, separator = "\n")
@@ -341,7 +341,7 @@ sealed class TypeInfo {
error(pointed) error(pointed)
override fun cToBridged(expr: String) = error(pointed) override fun cToBridged(expr: String) = error(pointed)
// TODO: this method must not exist // TODO: this method must not exist.
override fun constructPointedType(valueType: KotlinType): KotlinClassifierType = error(pointed) override fun constructPointedType(valueType: KotlinType): KotlinClassifierType = error(pointed)
} }
} }
@@ -231,7 +231,7 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
"$messenger(${messengerArguments.joinToString()})" "$messenger(${messengerArguments.joinToString()})"
} }
bodyGenerator.out("return $result") bodyGenerator.returnResult(result)
this.implementationTemplate = genImplementationTemplate(stubGenerator) this.implementationTemplate = genImplementationTemplate(stubGenerator)
this.bodyLines = bodyGenerator.build() this.bodyLines = bodyGenerator.build()
@@ -191,7 +191,7 @@ class SimpleBridgeGeneratorImpl(
kotlinExpr = "objc_retainAutoreleaseReturnValue($kotlinExpr)" kotlinExpr = "objc_retainAutoreleaseReturnValue($kotlinExpr)"
// (Objective-C does the same for returned pointers). // (Objective-C does the same for returned pointers).
} }
out("return $kotlinExpr") returnResult(kotlinExpr)
}.forEach { }.forEach {
kotlinLines.add(" $it") kotlinLines.add(" $it")
} }
@@ -613,7 +613,6 @@ class StubGenerator(
private val cCallSymbolName: String? private val cCallSymbolName: String?
init { init {
// TODO: support dumpShims
val kotlinParameters = mutableListOf<Pair<String, KotlinType>>() val kotlinParameters = mutableListOf<Pair<String, KotlinType>>()
val bodyGenerator = KotlinCodeBuilder(scope = kotlinFile) val bodyGenerator = KotlinCodeBuilder(scope = kotlinFile)
val bridgeArguments = mutableListOf<TypedKotlinValue>() val bridgeArguments = mutableListOf<TypedKotlinValue>()
@@ -648,13 +647,12 @@ class StubGenerator(
} else if (representAsValuesRef != null) { } else if (representAsValuesRef != null) {
kotlinParameters.add(parameterName to representAsValuesRef) kotlinParameters.add(parameterName to representAsValuesRef)
bodyGenerator.pushMemScoped() bodyGenerator.pushMemScoped()
"$parameterName?.getPointer(memScope)" bodyGenerator.getNativePointer(parameterName)
} else { } else {
val mirror = mirror(parameter.type) val mirror = mirror(parameter.type)
kotlinParameters.add(parameterName to mirror.argType) kotlinParameters.add(parameterName to mirror.argType)
parameterName parameterName
} }
bridgeArguments.add(TypedKotlinValue(parameter.type, bridgeArgument)) bridgeArguments.add(TypedKotlinValue(parameter.type, bridgeArgument))
} }
@@ -667,7 +665,7 @@ class StubGenerator(
) { nativeValues -> ) { nativeValues ->
"${func.name}(${nativeValues.joinToString()})" "${func.name}(${nativeValues.joinToString()})"
} }
bodyGenerator.out("return $result") bodyGenerator.returnResult(result)
isCCall = false isCCall = false
cCallSymbolName = null cCallSymbolName = null
} else { } else {
@@ -295,6 +295,12 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
return LLVMAddFunction(llvmModule, "llvm.memset.p0i8.i32", functionType)!! return LLVMAddFunction(llvmModule, "llvm.memset.p0i8.i32", functionType)!!
} }
private fun importMemcpy(): LLVMValueRef {
val parameterTypes = cValuesOf(int8TypePtr, int8TypePtr, int32Type, int1Type)
val functionType = LLVMFunctionType(LLVMVoidType(), parameterTypes, 4, 0)
return LLVMAddFunction(llvmModule, "llvm.memcpy.p0i8.p0i8.i32", functionType)!!
}
internal fun externalFunction(name: String, type: LLVMTypeRef, origin: CompiledKonanModuleOrigin): LLVMValueRef { internal fun externalFunction(name: String, type: LLVMTypeRef, origin: CompiledKonanModuleOrigin): LLVMValueRef {
this.imports.add(origin) this.imports.add(origin)
@@ -463,6 +469,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
) )
val memsetFunction = importMemset() val memsetFunction = importMemset()
val memcpyFunction = importMemcpy()
val usedFunctions = mutableListOf<LLVMValueRef>() val usedFunctions = mutableListOf<LLVMValueRef>()
val usedGlobals = mutableListOf<LLVMValueRef>() val usedGlobals = mutableListOf<LLVMValueRef>()
@@ -77,6 +77,7 @@ internal enum class IntrinsicType {
INTEROP_NARROW, INTEROP_NARROW,
INTEROP_STATIC_C_FUNCTION, INTEROP_STATIC_C_FUNCTION,
INTEROP_FUNPTR_INVOKE, INTEROP_FUNPTR_INVOKE,
INTEROP_MEMORY_COPY,
// Worker // Worker
WORKER_EXECUTE WORKER_EXECUTE
} }
@@ -216,6 +217,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
IntrinsicType.LIST_OF_INTERNAL -> emitListOfInternal(callSite, args) IntrinsicType.LIST_OF_INTERNAL -> emitListOfInternal(callSite, args)
IntrinsicType.IDENTITY -> emitIdentity(args) IntrinsicType.IDENTITY -> emitIdentity(args)
IntrinsicType.GET_CONTINUATION -> emitGetContinuation() IntrinsicType.GET_CONTINUATION -> emitGetContinuation()
IntrinsicType.INTEROP_MEMORY_COPY -> emitMemoryCopy(callSite, args)
IntrinsicType.RETURN_IF_SUSPEND, IntrinsicType.RETURN_IF_SUSPEND,
IntrinsicType.INTEROP_BITS_TO_FLOAT, IntrinsicType.INTEROP_BITS_TO_FLOAT,
IntrinsicType.INTEROP_BITS_TO_DOUBLE, IntrinsicType.INTEROP_BITS_TO_DOUBLE,
@@ -377,6 +379,12 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
return codegen.theUnitInstanceRef.llvm return codegen.theUnitInstanceRef.llvm
} }
private fun FunctionGenerationContext.emitMemoryCopy(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
println("memcpy at ${callSite}")
args.map { println(llvm2string(it)) }
TODO("Implement me")
}
private fun extractConstUnsignedInt(value: LLVMValueRef): Long { private fun extractConstUnsignedInt(value: LLVMValueRef): Long {
assert(LLVMIsConstant(value) != 0) assert(LLVMIsConstant(value) != 0)
return LLVMConstIntGetZExtValue(value) return LLVMConstIntGetZExtValue(value)
@@ -27,9 +27,8 @@ internal interface ConstPointer : ConstValue {
} }
internal fun constPointer(value: LLVMValueRef) = object : ConstPointer { internal fun constPointer(value: LLVMValueRef) = object : ConstPointer {
init { init {
assert (LLVMIsConstant(value) == 1) assert(LLVMIsConstant(value) == 1)
} }
override val llvm = value override val llvm = value
@@ -209,7 +209,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
} else { } else {
methodTableRecords(irClass) methodTableRecords(irClass)
} }
val methodsPtr = staticData.placeGlobalConstArray("kmethods:$className", val methodsPtr = staticData.placeGlobalConstArray("kmethods:$className",
runtime.methodTableRecordType, methods) runtime.methodTableRecordType, methods)
@@ -243,7 +242,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
} }
fun vtable(irClass: IrClass): ConstArray { fun vtable(irClass: IrClass): ConstArray {
// TODO: compile-time resolution limits binary compatibility // TODO: compile-time resolution limits binary compatibility.
val vtableEntries = context.getVtableBuilder(irClass).vtableEntries.map { val vtableEntries = context.getVtableBuilder(irClass).vtableEntries.map {
val implementation = it.implementation val implementation = it.implementation
if (implementation == null || implementation.isExternalObjCClassMethod()) { if (implementation == null || implementation.isExternalObjCClassMethod()) {
@@ -264,7 +263,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
if (previous != null) if (previous != null)
throw AssertionError("Duplicate method table entry: functionName = '$functionName', hash = '${nameSignature.value}', entry1 = $previous, entry2 = $it") throw AssertionError("Duplicate method table entry: functionName = '$functionName', hash = '${nameSignature.value}', entry1 = $previous, entry2 = $it")
// TODO: compile-time resolution limits binary compatibility // TODO: compile-time resolution limits binary compatibility.
val implementation = it.implementation val implementation = it.implementation
val methodEntryPoint = implementation?.entryPointAddress val methodEntryPoint = implementation?.entryPointAddress
MethodTableRecord(nameSignature, methodEntryPoint) MethodTableRecord(nameSignature, methodEntryPoint)
@@ -961,6 +961,9 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
) )
} }
} }
IntrinsicType.INTEROP_MEMORY_COPY -> {
TODO("So far unsupported")
}
IntrinsicType.OBJC_INIT_BY -> { IntrinsicType.OBJC_INIT_BY -> {
val intrinsic = interop.objCObjectInitBy.name val intrinsic = interop.objCObjectInitBy.name