Simplify interop stubs and runtime. (#2627)
This commit is contained in:
@@ -68,33 +68,30 @@ internal object nativeMemUtils {
|
||||
}
|
||||
|
||||
fun getByteArray(source: NativePointed, dest: ByteArray, length: Int) {
|
||||
val clazz = ByteArray::class.java
|
||||
val baseOffset = unsafe.arrayBaseOffset(clazz).toLong();
|
||||
unsafe.copyMemory(null, source.address, dest, baseOffset, length.toLong())
|
||||
unsafe.copyMemory(null, source.address, dest, byteArrayBaseOffset, length.toLong())
|
||||
}
|
||||
|
||||
fun putByteArray(source: ByteArray, dest: NativePointed, length: Int) {
|
||||
val clazz = ByteArray::class.java
|
||||
val baseOffset = unsafe.arrayBaseOffset(clazz).toLong();
|
||||
unsafe.copyMemory(source, baseOffset, null, dest.address, length.toLong())
|
||||
unsafe.copyMemory(source, byteArrayBaseOffset, null, dest.address, length.toLong())
|
||||
}
|
||||
|
||||
fun getCharArray(source: NativePointed, dest: CharArray, length: Int) {
|
||||
val clazz = CharArray::class.java
|
||||
val baseOffset = unsafe.arrayBaseOffset(clazz).toLong();
|
||||
unsafe.copyMemory(null, source.address, dest, baseOffset, length.toLong() * 2)
|
||||
unsafe.copyMemory(null, source.address, dest, charArrayBaseOffset, length.toLong() * 2)
|
||||
}
|
||||
|
||||
fun putCharArray(source: CharArray, dest: NativePointed, length: Int) {
|
||||
val clazz = CharArray::class.java
|
||||
val baseOffset = unsafe.arrayBaseOffset(clazz).toLong();
|
||||
unsafe.copyMemory(source, baseOffset, null, dest.address, length.toLong() * 2)
|
||||
unsafe.copyMemory(source, charArrayBaseOffset, 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")
|
||||
inline fun<reified T> allocateInstance(): T {
|
||||
inline fun <reified T> allocateInstance(): T {
|
||||
return unsafe.allocateInstance(T::class.java) as T
|
||||
}
|
||||
|
||||
@@ -115,4 +112,7 @@ internal object nativeMemUtils {
|
||||
isAccessible = true
|
||||
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
|
||||
@PublishedApi internal fun NonNullNativePtr.toNativePtr() = this
|
||||
internal fun NativePtr.toNonNull(): NonNullNativePtr = this
|
||||
val nativeNullPtr: NativePtr = 0L
|
||||
|
||||
public val nativeNullPtr: NativePtr = 0L
|
||||
|
||||
// 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 {
|
||||
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");
|
||||
* 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.
|
||||
*/
|
||||
open class NativePointed internal constructor(rawPtr: NonNullNativePtr) {
|
||||
public open class NativePointed internal constructor(rawPtr: NonNullNativePtr) {
|
||||
var rawPtr = rawPtr.toNativePtr()
|
||||
internal set
|
||||
}
|
||||
|
||||
// `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
|
||||
|
||||
/**
|
||||
@@ -38,22 +38,22 @@ val NativePointed?.rawPtr: NativePtr
|
||||
*
|
||||
* @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())
|
||||
|
||||
fun interpretOpaquePointed(ptr: NativePtr): NativePointed = interpretPointed<OpaqueNativePointed>(ptr)
|
||||
fun interpretNullableOpaquePointed(ptr: NativePtr): NativePointed? = interpretNullablePointed<OpaqueNativePointed>(ptr)
|
||||
public fun interpretOpaquePointed(ptr: NativePtr): NativePointed = interpretPointed<OpaqueNativePointed>(ptr)
|
||||
public fun interpretNullableOpaquePointed(ptr: NativePtr): NativePointed? = interpretNullablePointed<OpaqueNativePointed>(ptr)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
@@ -67,26 +67,28 @@ abstract class CPointed(rawPtr: NativePtr) : NativePointed(rawPtr.toNonNull())
|
||||
* 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.
|
||||
*/
|
||||
abstract class CValuesRef<T : CPointed> {
|
||||
public abstract class CValuesRef<T : CPointed> {
|
||||
/**
|
||||
* If this reference is [CPointer], returns this pointer.
|
||||
* Otherwise copies the referenced values to [placement] and returns the pointer to the copy.
|
||||
* If this reference is [CPointer], returns this pointer, otherwise
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
override fun equals(other: Any?): Boolean {
|
||||
public override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is CValues<*>) return false
|
||||
|
||||
@@ -106,7 +108,7 @@ abstract class CValues<T : CVariable> : CValuesRef<T>() {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
public override fun hashCode(): Int {
|
||||
var result = 0
|
||||
for (byte in this.getBytes()) {
|
||||
result = result * 31 + byte
|
||||
@@ -114,10 +116,17 @@ abstract class CValues<T : CVariable> : CValuesRef<T>() {
|
||||
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.
|
||||
@@ -125,18 +134,18 @@ fun <T : CVariable> CValues<T>.placeTo(scope: AutofreeScope) = this.getPointer(s
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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].
|
||||
@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) {
|
||||
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)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
public override fun hashCode(): Int {
|
||||
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.
|
||||
*/
|
||||
val <T : CPointed> T.ptr: CPointer<T>
|
||||
public val <T : CPointed> T.ptr: CPointer<T>
|
||||
get() = interpretCPointer(this.rawPtr)!!
|
||||
|
||||
/**
|
||||
@@ -164,33 +173,33 @@ val <T : CPointed> T.ptr: CPointer<T>
|
||||
*
|
||||
* @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)
|
||||
|
||||
// `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
|
||||
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
typealias COpaquePointer = CPointer<out CPointed> // FIXME
|
||||
public typealias COpaquePointer = CPointer<out CPointed> // FIXME
|
||||
|
||||
/**
|
||||
* The variable containing a [COpaquePointer].
|
||||
*/
|
||||
typealias COpaquePointerVar = CPointerVarOf<COpaquePointer>
|
||||
public typealias COpaquePointerVar = CPointerVarOf<COpaquePointer>
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
@@ -207,7 +216,7 @@ abstract class CVariable(rawPtr: NativePtr) : CPointed(rawPtr) {
|
||||
* @param align the alignments in bytes that is enough for this data type.
|
||||
* 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 {
|
||||
require(size % align == 0L)
|
||||
@@ -216,24 +225,24 @@ abstract class CVariable(rawPtr: NativePtr) : CPointed(rawPtr) {
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : CVariable> sizeOf() = typeOf<T>().size
|
||||
inline fun <reified T : CVariable> alignOf() = typeOf<T>().align
|
||||
public inline fun <reified T : CVariable> sizeOf() = typeOf<T>().size
|
||||
public inline fun <reified T : CVariable> alignOf() = typeOf<T>().align
|
||||
|
||||
/**
|
||||
* 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)
|
||||
}
|
||||
|
||||
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)!!
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
}
|
||||
|
||||
@@ -245,83 +254,84 @@ sealed class CPrimitiveVar(rawPtr: NativePtr) : CVariable(rawPtr) {
|
||||
open class Type(size: Int) : CVariable.Type(size.toLong(), align = size)
|
||||
}
|
||||
|
||||
interface CEnum {
|
||||
val value: Any
|
||||
public interface CEnum {
|
||||
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
|
||||
// these classes are not supposed to be used directly, instead the typealiases are provided.
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
typealias BooleanVar = BooleanVarOf<Boolean>
|
||||
typealias ByteVar = ByteVarOf<Byte>
|
||||
typealias ShortVar = ShortVarOf<Short>
|
||||
typealias IntVar = IntVarOf<Int>
|
||||
typealias LongVar = LongVarOf<Long>
|
||||
typealias UByteVar = UByteVarOf<UByte>
|
||||
typealias UShortVar = UShortVarOf<UShort>
|
||||
typealias UIntVar = UIntVarOf<UInt>
|
||||
typealias ULongVar = ULongVarOf<ULong>
|
||||
typealias FloatVar = FloatVarOf<Float>
|
||||
typealias DoubleVar = DoubleVarOf<Double>
|
||||
public typealias BooleanVar = BooleanVarOf<Boolean>
|
||||
public typealias ByteVar = ByteVarOf<Byte>
|
||||
public typealias ShortVar = ShortVarOf<Short>
|
||||
public typealias IntVar = IntVarOf<Int>
|
||||
public typealias LongVar = LongVarOf<Long>
|
||||
public typealias UByteVar = UByteVarOf<UByte>
|
||||
public typealias UShortVar = UShortVarOf<UShort>
|
||||
public typealias UIntVar = UIntVarOf<UInt>
|
||||
public typealias ULongVar = ULongVarOf<ULong>
|
||||
public typealias FloatVar = FloatVarOf<Float>
|
||||
public typealias DoubleVar = DoubleVarOf<Double>
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
|
||||
var <T : Boolean> BooleanVarOf<T>.value: T
|
||||
public var <T : Boolean> BooleanVarOf<T>.value: T
|
||||
get() {
|
||||
val byte = nativeMemUtils.getByte(this)
|
||||
return byte.toBoolean() as T
|
||||
@@ -329,78 +339,78 @@ var <T : Boolean> BooleanVarOf<T>.value: T
|
||||
set(value) = nativeMemUtils.putByte(this, value.toByte())
|
||||
|
||||
@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")
|
||||
inline fun Byte.toBoolean() = (this - 0 != 0)
|
||||
public inline fun Byte.toBoolean() = (this.toInt() != 0)
|
||||
|
||||
@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
|
||||
set(value) = nativeMemUtils.putByte(this, value)
|
||||
|
||||
@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
|
||||
set(value) = nativeMemUtils.putShort(this, value)
|
||||
|
||||
@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
|
||||
set(value) = nativeMemUtils.putInt(this, value)
|
||||
|
||||
@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
|
||||
set(value) = nativeMemUtils.putLong(this, value)
|
||||
|
||||
@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
|
||||
set(value) = nativeMemUtils.putByte(this, value.toByte())
|
||||
|
||||
@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
|
||||
set(value) = nativeMemUtils.putShort(this, value.toShort())
|
||||
|
||||
@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
|
||||
set(value) = nativeMemUtils.putInt(this, value.toInt())
|
||||
|
||||
@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
|
||||
set(value) = nativeMemUtils.putLong(this, value.toLong())
|
||||
|
||||
// TODO: ensure native floats have the appropriate binary representation
|
||||
|
||||
@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
|
||||
set(value) = nativeMemUtils.putFloat(this, value)
|
||||
|
||||
@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
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@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?
|
||||
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
|
||||
*/
|
||||
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
|
||||
set(value) {
|
||||
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) {
|
||||
0L // optimization for JVM impl which uses reflection for now.
|
||||
} else {
|
||||
@@ -424,40 +434,40 @@ inline operator fun <reified T : CVariable> CPointer<T>.get(index: Long): T {
|
||||
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")
|
||||
@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)
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@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()
|
||||
|
||||
@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
|
||||
|
||||
@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
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
@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
|
||||
}
|
||||
|
||||
typealias CArrayPointer<T> = CPointer<T>
|
||||
typealias CArrayPointerVar<T> = CPointerVar<T>
|
||||
public typealias CArrayPointer<T> = CPointer<T>
|
||||
public typealias CArrayPointerVar<T> = CPointerVar<T>
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
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 {
|
||||
fun free(mem: NativePtr)
|
||||
public interface NativeFreeablePlacement : NativePlacement {
|
||||
public fun free(mem: NativePtr)
|
||||
}
|
||||
|
||||
fun NativeFreeablePlacement.free(pointer: CPointer<*>) = this.free(pointer.rawValue)
|
||||
fun NativeFreeablePlacement.free(pointed: NativePointed) = this.free(pointed.rawPtr)
|
||||
public fun NativeFreeablePlacement.free(pointer: CPointer<*>) = this.free(pointer.rawValue)
|
||||
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 free(mem: NativePtr) = nativeMemUtils.free(mem)
|
||||
@@ -38,7 +38,7 @@ object nativeHeap : NativeFreeablePlacement {
|
||||
|
||||
private typealias Deferred = () -> Unit
|
||||
|
||||
open class DeferScope {
|
||||
public open class DeferScope {
|
||||
|
||||
@PublishedApi
|
||||
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
|
||||
}
|
||||
|
||||
open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : AutofreeScope() {
|
||||
public open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : AutofreeScope() {
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ class Arena(parent: NativeFreeablePlacement = nativeHeap) : ArenaBase(parent) {
|
||||
*
|
||||
* @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()
|
||||
|
||||
@PublishedApi
|
||||
@@ -118,7 +118,7 @@ internal fun NativePlacement.alloc(type: CVariable.Type): NativePointed =
|
||||
*
|
||||
* @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() }
|
||||
|
||||
/**
|
||||
@@ -126,7 +126,7 @@ inline fun <reified T : CVariable> NativePlacement.alloc(initialize: T.() -> Uni
|
||||
*
|
||||
* @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
|
||||
|
||||
/**
|
||||
@@ -134,7 +134,7 @@ inline fun <reified T : CVariable> NativePlacement.allocArray(length: Long): CAr
|
||||
*
|
||||
* @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())
|
||||
|
||||
/**
|
||||
@@ -142,7 +142,7 @@ inline fun <reified T : CVariable> NativePlacement.allocArray(length: Int): CArr
|
||||
*
|
||||
* @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> {
|
||||
val res = allocArray<T>(length)
|
||||
|
||||
@@ -158,9 +158,8 @@ inline fun <reified T : CVariable> NativePlacement.allocArray(length: Long,
|
||||
*
|
||||
* @param T must not be abstract
|
||||
*/
|
||||
inline fun <reified T : CVariable> NativePlacement.allocArray(length: Int,
|
||||
initializer: T.(index: Int)->Unit): CArrayPointer<T> =
|
||||
allocArray(length.toLong()) { index ->
|
||||
public inline fun <reified T : CVariable> NativePlacement.allocArray(
|
||||
length: Int, initializer: T.(index: Int)->Unit): CArrayPointer<T> = allocArray(length.toLong()) { index ->
|
||||
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.
|
||||
*/
|
||||
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)
|
||||
elements.forEachIndexed { index, value ->
|
||||
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.
|
||||
*/
|
||||
fun <T : CPointed> NativePlacement.allocArrayOfPointersTo(vararg elements: T?) =
|
||||
public fun <T : CPointed> NativePlacement.allocArrayOfPointersTo(vararg elements: T?) =
|
||||
allocArrayOfPointersTo(listOf(*elements))
|
||||
|
||||
/**
|
||||
* 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>> {
|
||||
|
||||
return allocArrayOf(listOf(*elements))
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>> {
|
||||
|
||||
val res = allocArray<CPointerVarOf<T>>(elements.size)
|
||||
@@ -206,13 +204,13 @@ inline fun <reified T : CPointer<*>>
|
||||
return res
|
||||
}
|
||||
|
||||
fun NativePlacement.allocArrayOf(elements: ByteArray): CArrayPointer<ByteVar> {
|
||||
public fun NativePlacement.allocArrayOf(elements: ByteArray): CArrayPointer<ByteVar> {
|
||||
val result = allocArray<ByteVar>(elements.size)
|
||||
nativeMemUtils.putByteArray(elements, result.pointed, elements.size)
|
||||
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)
|
||||
var index = 0
|
||||
while (index < elements.size) {
|
||||
@@ -222,48 +220,67 @@ fun NativePlacement.allocArrayOf(vararg elements: Float): CArrayPointer<FloatVar
|
||||
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> {
|
||||
val result = scope.alloc(size, align)
|
||||
nativeMemUtils.zeroMemory(result, size)
|
||||
return interpretCPointer(result.rawPtr)!!
|
||||
return place(interpretCPointer(scope.alloc(size, align).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> =
|
||||
zeroValue<T>(sizeOf<T>().toInt(), alignOf<T>())
|
||||
public inline fun <reified T : CVariable> zeroValue(): CValue<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> {
|
||||
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> {
|
||||
public fun <T : CVariable> CPointed.readValues(size: Int, align: Int): CValues<T> {
|
||||
val bytes = ByteArray(size)
|
||||
nativeMemUtils.getByteArray(this, bytes, size)
|
||||
|
||||
return object : CValues<T>() {
|
||||
override fun getPointer(scope: AutofreeScope): CPointer<T> = scope.placeBytes(bytes, align)
|
||||
override val size get() = bytes.size
|
||||
return object : CValue<T>() {
|
||||
// Optimization to avoid unneeded virtual calls in base class implementation.
|
||||
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>())
|
||||
|
||||
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())
|
||||
nativeMemUtils.getByteArray(this, bytes, size.toInt())
|
||||
|
||||
return object : CValue<T>() {
|
||||
override fun getPointer(scope: AutofreeScope): CPointer<T> = scope.placeBytes(bytes, align)
|
||||
override val size get() = bytes.size
|
||||
override fun place(placement: CPointer<T>): CPointer<T> {
|
||||
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.
|
||||
// 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) {
|
||||
// TODO: probably CValue must be redesigned.
|
||||
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)
|
||||
public fun <T: CVariable> CValue<T>.write(location: NativePtr) {
|
||||
this.place(interpretCPointer(location)!!)
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
fun <T : CVariable> CValues<T>.getBytes(): ByteArray = memScoped {
|
||||
public fun <T : CVariable> CValues<T>.getBytes(): ByteArray = memScoped {
|
||||
val result = ByteArray(size)
|
||||
|
||||
nativeMemUtils.getByteArray(
|
||||
source = this@getBytes.placeTo(memScope).reinterpret<ByteVar>().pointed,
|
||||
dest = result,
|
||||
length = result.size
|
||||
)
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
}
|
||||
|
||||
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.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)
|
||||
|
||||
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)
|
||||
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:
|
||||
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> =
|
||||
createValues(elements.size) { index -> this.value = elements[index] }
|
||||
|
||||
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
|
||||
override val size get() = 1 * elements.size
|
||||
override val align get() = 1
|
||||
}
|
||||
|
||||
fun cValuesOf(vararg elements: Double): CValues<DoubleVar> =
|
||||
public fun cValuesOf(vararg elements: Short): CValues<ShortVar> =
|
||||
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] }
|
||||
|
||||
fun ByteArray.toCValues() = cValuesOf(*this)
|
||||
fun ShortArray.toCValues() = cValuesOf(*this)
|
||||
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)
|
||||
public fun cValuesOf(vararg elements: Long): CValues<LongVar> =
|
||||
createValues(elements.size) { index -> this.value = elements[index] }
|
||||
|
||||
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>() {
|
||||
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> {
|
||||
val result = scope.allocArray<ByteVar>(bytes.size + 1)
|
||||
nativeMemUtils.putByteArray(bytes, result.pointed, bytes.size)
|
||||
result[bytes.size] = 0.toByte()
|
||||
return result
|
||||
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
|
||||
}
|
||||
override fun place(placement: CPointer<ByteVar>): CPointer<ByteVar> {
|
||||
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].
|
||||
*/
|
||||
val String.cstr: CValues<ByteVar>
|
||||
public val String.cstr: CValues<ByteVar>
|
||||
get() = CString(encodeToUtf8(this))
|
||||
|
||||
/**
|
||||
* Convert this list of Kotlin strings to C array of C strings,
|
||||
* 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) })
|
||||
|
||||
/**
|
||||
* Convert this array of Kotlin strings to C array of C strings,
|
||||
* 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) })
|
||||
|
||||
|
||||
private class WCString(val chars: CharArray): CValues<UShortVar>() {
|
||||
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> {
|
||||
val result = scope.allocArray<UShortVar>(chars.size + 1)
|
||||
nativeMemUtils.putCharArray(chars, result.pointed, chars.size)
|
||||
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
|
||||
}
|
||||
|
||||
override fun place(placement: CPointer<UShortVar>): CPointer<UShortVar> {
|
||||
nativeMemUtils.putCharArray(chars, placement.pointed, chars.size)
|
||||
// TODO: fix, after KT-29627 is fixed.
|
||||
nativeMemUtils.putShort((result + chars.size)!!.pointed, 0)
|
||||
return result
|
||||
nativeMemUtils.putShort((placement + chars.size)!!.pointed, 0)
|
||||
return placement
|
||||
}
|
||||
}
|
||||
|
||||
val String.wcstr: CValues<UShortVar>
|
||||
public val String.wcstr: CValues<UShortVar>
|
||||
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.
|
||||
*/
|
||||
// TODO: optimize
|
||||
fun CPointer<ByteVar>.toKString(): String {
|
||||
public fun CPointer<ByteVar>.toKString(): String {
|
||||
val nativeBytes = this
|
||||
|
||||
var length = 0
|
||||
@@ -425,7 +444,7 @@ fun CPointer<ByteVar>.toKString(): String {
|
||||
return decodeFromUtf8(bytes)
|
||||
}
|
||||
|
||||
class MemScope : ArenaBase() {
|
||||
public class MemScope : ArenaBase() {
|
||||
|
||||
val memScope: MemScope
|
||||
get() = this
|
||||
@@ -440,7 +459,7 @@ class MemScope : ArenaBase() {
|
||||
* Runs given [block] providing allocation of memory
|
||||
* 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()
|
||||
try {
|
||||
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)
|
||||
nativeMemUtils.getByteArray(this.reinterpret<ByteVar>().pointed, result, count)
|
||||
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 {
|
||||
val ptr = malloc(size, align)
|
||||
if (ptr == nativeNullPtr) {
|
||||
@@ -157,4 +168,4 @@ private external fun cfree(ptr: NativePtr)
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_READ_BITS)
|
||||
external fun readBits(ptr: NativePtr, offset: Long, size: Int, signed: Boolean): Long
|
||||
@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)
|
||||
|
||||
+41
-18
@@ -34,14 +34,25 @@ inline fun buildNativeCodeLines(scope: NativeScope, block: NativeCodeBuilder.()
|
||||
return builder.lines
|
||||
}
|
||||
|
||||
class KotlinCodeBuilder(val scope: KotlinScope) {
|
||||
private val lines = mutableListOf<String>()
|
||||
private class Block(val nesting: Int, val start: String, val end: String) {
|
||||
val prologue = mutableListOf<String>()
|
||||
val body = mutableListOf<String>()
|
||||
val epilogue = mutableListOf<String>()
|
||||
|
||||
private val freeStack = mutableListOf<String>()
|
||||
private val nesting get() = freeStack.size
|
||||
fun indent(line: String) = " ".repeat(nesting) + line
|
||||
fun indentBraces(line: String) = " ".repeat(nesting - 1) + line
|
||||
}
|
||||
|
||||
class KotlinCodeBuilder(val scope: KotlinScope) {
|
||||
|
||||
private val blocks = mutableListOf<Block>()
|
||||
|
||||
init {
|
||||
pushBlock("", "")
|
||||
}
|
||||
|
||||
fun out(line: String) {
|
||||
lines.add(" ".repeat(nesting) + line)
|
||||
currentBlock().body += line
|
||||
}
|
||||
|
||||
private var memScoped = false
|
||||
@@ -52,24 +63,36 @@ class KotlinCodeBuilder(val scope: KotlinScope) {
|
||||
}
|
||||
}
|
||||
|
||||
fun pushBlock(line: String, free: String = "") {
|
||||
out(line)
|
||||
freeStack.add(free)
|
||||
fun getNativePointer(name: String): String {
|
||||
return "$name?.getPointer(memScope)"
|
||||
}
|
||||
|
||||
private fun popBlocks() {
|
||||
while (freeStack.isNotEmpty()) {
|
||||
val free = freeStack.last()
|
||||
freeStack.removeAt(freeStack.lastIndex)
|
||||
out("} $free".trim())
|
||||
}
|
||||
fun returnResult(result: String) {
|
||||
currentBlock().body += "return $result"
|
||||
}
|
||||
|
||||
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> {
|
||||
this.popBlocks()
|
||||
val result = this.lines.toList()
|
||||
this.lines.clear()
|
||||
return result
|
||||
val lines = mutableListOf<String>()
|
||||
emitBlockAndNested(0, lines)
|
||||
return lines.toList()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -57,8 +57,9 @@ class MappingBridgeGeneratorImpl(
|
||||
is RecordType -> {
|
||||
val mirror = mirror(declarationMapper, returnType)
|
||||
val tmpVarName = kniRetVal
|
||||
// We clear in the finally block.
|
||||
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"))
|
||||
BridgedType.VOID
|
||||
}
|
||||
|
||||
+2
-2
@@ -315,7 +315,7 @@ sealed class TypeInfo {
|
||||
val objCBlock = "((__bridge $blockType)${nativeValues.last()})"
|
||||
"$objCBlock(${nativeValues.dropLast(1).joinToString()})"
|
||||
}.let {
|
||||
codeBuilder.out("return $it")
|
||||
codeBuilder.returnResult(it)
|
||||
}
|
||||
|
||||
codeBuilder.build().joinTo(this, separator = "\n")
|
||||
@@ -341,7 +341,7 @@ sealed class TypeInfo {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -231,7 +231,7 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
|
||||
|
||||
"$messenger(${messengerArguments.joinToString()})"
|
||||
}
|
||||
bodyGenerator.out("return $result")
|
||||
bodyGenerator.returnResult(result)
|
||||
|
||||
this.implementationTemplate = genImplementationTemplate(stubGenerator)
|
||||
this.bodyLines = bodyGenerator.build()
|
||||
|
||||
+1
-1
@@ -191,7 +191,7 @@ class SimpleBridgeGeneratorImpl(
|
||||
kotlinExpr = "objc_retainAutoreleaseReturnValue($kotlinExpr)"
|
||||
// (Objective-C does the same for returned pointers).
|
||||
}
|
||||
out("return $kotlinExpr")
|
||||
returnResult(kotlinExpr)
|
||||
}.forEach {
|
||||
kotlinLines.add(" $it")
|
||||
}
|
||||
|
||||
+2
-4
@@ -613,7 +613,6 @@ class StubGenerator(
|
||||
private val cCallSymbolName: String?
|
||||
|
||||
init {
|
||||
// TODO: support dumpShims
|
||||
val kotlinParameters = mutableListOf<Pair<String, KotlinType>>()
|
||||
val bodyGenerator = KotlinCodeBuilder(scope = kotlinFile)
|
||||
val bridgeArguments = mutableListOf<TypedKotlinValue>()
|
||||
@@ -648,13 +647,12 @@ class StubGenerator(
|
||||
} else if (representAsValuesRef != null) {
|
||||
kotlinParameters.add(parameterName to representAsValuesRef)
|
||||
bodyGenerator.pushMemScoped()
|
||||
"$parameterName?.getPointer(memScope)"
|
||||
bodyGenerator.getNativePointer(parameterName)
|
||||
} else {
|
||||
val mirror = mirror(parameter.type)
|
||||
kotlinParameters.add(parameterName to mirror.argType)
|
||||
parameterName
|
||||
}
|
||||
|
||||
bridgeArguments.add(TypedKotlinValue(parameter.type, bridgeArgument))
|
||||
}
|
||||
|
||||
@@ -667,7 +665,7 @@ class StubGenerator(
|
||||
) { nativeValues ->
|
||||
"${func.name}(${nativeValues.joinToString()})"
|
||||
}
|
||||
bodyGenerator.out("return $result")
|
||||
bodyGenerator.returnResult(result)
|
||||
isCCall = false
|
||||
cCallSymbolName = null
|
||||
} else {
|
||||
|
||||
+7
@@ -295,6 +295,12 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
||||
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 {
|
||||
this.imports.add(origin)
|
||||
|
||||
@@ -463,6 +469,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
||||
)
|
||||
|
||||
val memsetFunction = importMemset()
|
||||
val memcpyFunction = importMemcpy()
|
||||
|
||||
val usedFunctions = mutableListOf<LLVMValueRef>()
|
||||
val usedGlobals = mutableListOf<LLVMValueRef>()
|
||||
|
||||
+8
@@ -77,6 +77,7 @@ internal enum class IntrinsicType {
|
||||
INTEROP_NARROW,
|
||||
INTEROP_STATIC_C_FUNCTION,
|
||||
INTEROP_FUNPTR_INVOKE,
|
||||
INTEROP_MEMORY_COPY,
|
||||
// Worker
|
||||
WORKER_EXECUTE
|
||||
}
|
||||
@@ -216,6 +217,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
IntrinsicType.LIST_OF_INTERNAL -> emitListOfInternal(callSite, args)
|
||||
IntrinsicType.IDENTITY -> emitIdentity(args)
|
||||
IntrinsicType.GET_CONTINUATION -> emitGetContinuation()
|
||||
IntrinsicType.INTEROP_MEMORY_COPY -> emitMemoryCopy(callSite, args)
|
||||
IntrinsicType.RETURN_IF_SUSPEND,
|
||||
IntrinsicType.INTEROP_BITS_TO_FLOAT,
|
||||
IntrinsicType.INTEROP_BITS_TO_DOUBLE,
|
||||
@@ -377,6 +379,12 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
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 {
|
||||
assert(LLVMIsConstant(value) != 0)
|
||||
return LLVMConstIntGetZExtValue(value)
|
||||
|
||||
+1
-2
@@ -27,9 +27,8 @@ internal interface ConstPointer : ConstValue {
|
||||
}
|
||||
|
||||
internal fun constPointer(value: LLVMValueRef) = object : ConstPointer {
|
||||
|
||||
init {
|
||||
assert (LLVMIsConstant(value) == 1)
|
||||
assert(LLVMIsConstant(value) == 1)
|
||||
}
|
||||
|
||||
override val llvm = value
|
||||
|
||||
+2
-3
@@ -209,7 +209,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
} else {
|
||||
methodTableRecords(irClass)
|
||||
}
|
||||
|
||||
val methodsPtr = staticData.placeGlobalConstArray("kmethods:$className",
|
||||
runtime.methodTableRecordType, methods)
|
||||
|
||||
@@ -243,7 +242,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
}
|
||||
|
||||
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 implementation = it.implementation
|
||||
if (implementation == null || implementation.isExternalObjCClassMethod()) {
|
||||
@@ -264,7 +263,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
if (previous != null)
|
||||
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 methodEntryPoint = implementation?.entryPointAddress
|
||||
MethodTableRecord(nameSignature, methodEntryPoint)
|
||||
|
||||
+3
@@ -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 -> {
|
||||
val intrinsic = interop.objCObjectInitBy.name
|
||||
|
||||
|
||||
Reference in New Issue
Block a user