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
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(
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
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
import org.jetbrains.skia.ExternalSymbolName
actual abstract class RefCnt : Managed {
actual protected constructor(ptr: NativePointer): super(ptr, NullPointer, false) {
println("TODO: implement native RefCnt")
protected actual constructor(ptr: NativePointer) : super(ptr, _FinalizerHolder.PTR) {}
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
import kotlin.native.concurrent.AtomicLong
actual object Stats {
val enabled = false
val nativeCalls = AtomicLong(0)
val allocated = AtomicLong(0)
actual fun onNativeCall() {
// TODO
if (enabled) nativeCalls.increment()
}
actual fun onAllocated(className: String) {
// TODO
if (enabled) {
allocated.increment()
println("AFTER ALLOC: $allocated")
}
}
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) {
}
fun dispose() {
println("Need to free surface")
println("Need to free renderTarget")
// surface?.close()
// 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