Skip to content

Commit

Permalink
Add defer support to memScope
Browse files Browse the repository at this point in the history
  • Loading branch information
SvyatoslavScherbina committed Sep 26, 2017
1 parent 9609a10 commit 2217be4
Showing 1 changed file with 44 additions and 12 deletions.
56 changes: 44 additions & 12 deletions Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,41 @@ object nativeHeap : NativeFreeablePlacement {
override fun free(mem: NativePtr) = nativeMemUtils.free(mem)
}

private typealias Deferred = () -> Unit

open class DeferScope {

@PublishedApi
internal var topDeferred: Deferred? = null

internal fun executeAllDeferred() {
topDeferred?.let {
it.invoke()
topDeferred = null
}
}

inline fun defer(crossinline block: () -> Unit) {
val currentTop = topDeferred
topDeferred = {
try {
block()
} finally {
// TODO: it is possible to implement chaining without recursion,
// but it would require using an anonymous object here
// which is not yet supported in Kotlin Native inliner.
currentTop?.invoke()
}
}
}
}

// TODO: implement optimally
class Arena(private val parent: NativeFreeablePlacement = nativeHeap) : NativePlacement {
open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : NativePlacement, DeferScope() {

private val allocatedChunks = ArrayList<NativePointed>()

override fun alloc(size: Long, align: Int): NativePointed {
final override fun alloc(size: Long, align: Int): NativePointed {
val res = parent.alloc(size, align)
try {
allocatedChunks.add(res)
Expand All @@ -52,7 +81,10 @@ class Arena(private val parent: NativeFreeablePlacement = nativeHeap) : NativePl
}
}

fun clear() {
@PublishedApi
internal fun clearImpl() {
this.executeAllDeferred()

allocatedChunks.forEach {
parent.free(it)
}
Expand All @@ -62,6 +94,10 @@ class Arena(private val parent: NativeFreeablePlacement = nativeHeap) : NativePl

}

class Arena(parent: NativeFreeablePlacement = nativeHeap) : ArenaBase(parent) {
fun clear() = this.clearImpl()
}

/**
* Allocates variable of given type.
*
Expand Down Expand Up @@ -355,18 +391,14 @@ fun CPointer<ByteVar>.toKString(): String {
return decodeFromUtf8(bytes)
}

class MemScope : NativePlacement {
class MemScope : ArenaBase() {

private val arena = Arena()

override fun alloc(size: Long, align: Int) = arena.alloc(size, align)

fun clear() = arena.clear()

val memScope: NativePlacement
val memScope: MemScope
get() = this
}

// TODO: consider renaming `memScoped` because it now supports `defer`.

/**
* Runs given [block] providing allocation of memory
* which will be automatically disposed at the end of this scope.
Expand All @@ -376,7 +408,7 @@ inline fun <R> memScoped(block: MemScope.()->R): R {
try {
return memScope.block()
} finally {
memScope.clear()
memScope.clearImpl()
}
}

Expand Down

0 comments on commit 2217be4

Please sign in to comment.