Unverified Commit 6fe68286 authored by alexander-gorshenev's avatar alexander-gorshenev Committed by GitHub

Native memory management (#182)

* Native memory management

* Moved native Managed from AtomicLong to AtomicNativePtr
parent 40bf4ebe
#include <iostream>
#include "common.h"
typedef void (*FreeFunction)(void*);
extern "C" void org_jetbrains_skia_impl_Managed__1nInvokeFinalizer
(jlong finalizerPtr, jlong ptr) {
void* instance = reinterpret_cast<void*>(static_cast<uintptr_t>(ptr));
FreeFunction finalizer = reinterpret_cast<FreeFunction>(static_cast<uintptr_t>(finalizerPtr));
finalizer(instance);
}
#include "common.h"
#include "SkRefCnt.h"
class SkRefCntHack {
public:
void* x;
mutable std::atomic<int32_t> fRefCnt;
};
void unrefSkRefCnt(SkRefCnt* p) {
p->unref();
}
extern "C" jlong org_jetbrains_skia_impl_RefCnt__1nGetFinalizer() {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&unrefSkRefCnt));
}
extern "C" jint org_jetbrains_skia_impl_RefCnt__1nGetRefCount(jlong ptr) {
SkRefCnt* instance = reinterpret_cast<SkRefCnt*>(static_cast<uintptr_t>(ptr));
return reinterpret_cast<SkRefCntHack*>(instance)->fRefCnt.load(std::memory_order_relaxed);
}
package org.jetbrains.skia.impl package org.jetbrains.skia.impl
import kotlinx.cinterop.nativeNullPtr
import org.jetbrains.skia.ExternalSymbolName
import kotlin.native.concurrent.AtomicNativePtr
import kotlin.native.concurrent.freeze
import kotlin.native.internal.createCleaner
private class FinalizationThunk(private val finalizer: NativePointer, val className: String, obj: NativePointer) {
private var obj = AtomicNativePtr(obj)
fun clean() {
val ptr = obj.value
if (ptr != nativeNullPtr && obj.compareAndSet(ptr, nativeNullPtr)) {
Stats.onDeallocated(className)
Stats.onNativeCall()
_nInvokeFinalizer(finalizer, ptr)
}
}
val isActive get() =
obj.value != nativeNullPtr
}
actual abstract class Managed actual constructor( actual abstract class Managed actual constructor(
ptr: NativePointer, finalizer: NativePointer, managed: Boolean) : Native(ptr) { ptr: NativePointer, finalizer: NativePointer, managed: Boolean) : Native(ptr) {
actual open fun close(): Unit = TODO()
private val thunk: FinalizationThunk? = if (managed) {
require(ptr != NullPointer) { "Managed ptr is nullptr" }
require(finalizer != NullPointer) { "Managed finalizer is nullptr" }
val className = this::class.simpleName ?: "<kotlin>"
Stats.onAllocated(className)
FinalizationThunk(finalizer, className, ptr).freeze()
} else null
@OptIn(ExperimentalStdlibApi::class)
private val cleaner = if (managed) {
createCleaner(thunk) {
it?.clean()
}
} else null
actual open fun close() {
require(_ptr != NullPointer) {
"Object already closed: ${this::class.simpleName}, _ptr=$_ptr"
}
requireNotNull(thunk) {
"Object is not managed in K/N runtime, can't close(): ${this::class.simpleName}, _ptr=$_ptr"
}
require(thunk.isActive) {
"Object is closed already, can't close(): ${this::class.simpleName}, _ptr=$_ptr"
}
thunk.clean()
_ptr = NullPointer
}
actual open val isClosed: Boolean actual open val isClosed: Boolean
get() = _ptr == NullPointer get() = _ptr == NullPointer
} }
\ No newline at end of file
@ExternalSymbolName("org_jetbrains_skia_impl_Managed__1nInvokeFinalizer")
external fun _nInvokeFinalizer(finalizer: NativePointer, ptr: NativePointer)
package org.jetbrains.skia.impl package org.jetbrains.skia.impl
import org.jetbrains.skia.ExternalSymbolName
actual abstract class RefCnt : Managed { actual abstract class RefCnt : Managed {
actual protected constructor(ptr: NativePointer): super(ptr, NullPointer, false) { protected actual constructor(ptr: NativePointer) : super(ptr, _FinalizerHolder.PTR) {}
println("TODO: implement native RefCnt") protected actual constructor(ptr: NativePointer, allowClose: Boolean) : super(ptr, _FinalizerHolder.PTR, allowClose)
val refCount: Int
get() = try {
Stats.onNativeCall()
_nGetRefCount(_ptr)
} finally {
reachabilityBarrier(this)
}
override fun toString(): String {
val s = super.toString()
return s.substring(0, s.length - 1) + ", refCount=" + refCount + ")"
} }
actual protected constructor(ptr: NativePointer, allowClose: Boolean): super(ptr, NullPointer, allowClose) {
println("TODO: implement native RefCnt") private object _FinalizerHolder {
val PTR = _nGetFinalizer()
} }
} }
\ No newline at end of file
@ExternalSymbolName("org_jetbrains_skia_impl_RefCnt__1nGetFinalizer")
private external fun _nGetFinalizer(): NativePointer
@ExternalSymbolName("org_jetbrains_skia_impl_RefCnt__1nGetRefCount")
private external fun _nGetRefCount(ptr: NativePointer): Int
package org.jetbrains.skia.impl package org.jetbrains.skia.impl
import kotlin.native.concurrent.AtomicLong
actual object Stats { actual object Stats {
val enabled = false
val nativeCalls = AtomicLong(0)
val allocated = AtomicLong(0)
actual fun onNativeCall() { actual fun onNativeCall() {
// TODO if (enabled) nativeCalls.increment()
} }
actual fun onAllocated(className: String) { actual fun onAllocated(className: String) {
// TODO if (enabled) {
allocated.increment()
println("AFTER ALLOC: $allocated")
}
} }
actual fun onDeallocated(className: String) { actual fun onDeallocated(className: String) {
// TODO if (enabled) {
allocated.decrement()
println("AFTER DEALLOC: $allocated")
}
} }
} }
\ No newline at end of file
...@@ -43,9 +43,7 @@ internal abstract class ContextHandler(val layer: HardwareLayer) { ...@@ -43,9 +43,7 @@ internal abstract class ContextHandler(val layer: HardwareLayer) {
} }
fun dispose() { fun dispose() {
println("Need to free surface") surface?.close()
println("Need to free renderTarget") renderTarget?.close()
// surface?.close()
// renderTarget?.close()
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment