diff --git a/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/JniScope.kt b/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/JniScope.kt index c4deff9a4906b470c834ebc6ec7ab6b1e7018ded..16598d1fb207f6549124b5c3d435673bd2b05ba0 100644 --- a/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/JniScope.kt +++ b/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/JniScope.kt @@ -29,9 +29,6 @@ import kotlinx.cinterop.CVariable import kotlinx.cinterop.ExperimentalForeignApi value class JniScope(val env: JniEnvironment) { - inline val runtime: JvmRuntime? - get() = JvmRuntime.get(env) - fun jstring.toKString(): String = toKString(env) fun String.toJString(): jstring = toJString(env) @@ -110,6 +107,11 @@ value class JniScope(val env: JniEnvironment) { val JvmField.instance: JvmObject get() = getInstance(env) + fun JvmMethod.callVoid( + instance: JvmObject = JvmObject.NULL, + closure: ArgumentScope.() -> Unit = {} + ) = callVoid(env, instance, closure) + fun JvmMethod.callByte( instance: JvmObject = JvmObject.NULL, closure: ArgumentScope.() -> Unit = {} @@ -430,6 +432,18 @@ value class JniScope(val env: JniEnvironment) { get() = getIterator(env) inline val JvmObjectArray.view: JvmObjectArrayView get() = getView(env) + + inline val runtime: JvmRuntime + get() = JvmRuntime.get(env) + inline val JvmRuntime.availableProcessors: Int + get() = getAvailableProcessors(env) + inline val JvmRuntime.totalMemory: Int + get() = getTotalMemory(env) + inline val JvmRuntime.maxMemory: Int + get() = getMaxMemory(env) + + fun JvmRuntime.freeMemory() = freeMemory(env) + fun JvmRuntime.gc() = gc(env) } @OptIn(UnsafeJniApi::class) diff --git a/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/JvmMethod.kt b/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/JvmMethod.kt index 328a17bb2e72740577b0c0b699d6bc16ff1cad69..27619f2ceda1b81608fc2cfa5599483642fe830b 100644 --- a/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/JvmMethod.kt +++ b/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/JvmMethod.kt @@ -186,25 +186,42 @@ class JvmMethod( ) } + @OptIn(UnsafeJniApi::class, InternalJniApi::class) + inline fun callVoid( + env: JniEnvironment, + instance: JvmObject = JvmObject.NULL, + args: ArgumentScope.() -> Unit = {} + ) = memScoped { + when (descriptor.callType) { // @formatter:off + CallType.STATIC -> env.pointed?.CallStaticVoidMethodA?.invoke( + env.ptr, enclosingClass.handle, id, allocArgs(args) + ) + CallType.VIRTUAL -> env.pointed?.CallVoidMethodA?.invoke( + env.ptr, instance.handle, id, allocArgs(args) + ) + CallType.DIRECT -> env.pointed?.CallNonvirtualVoidMethodA?.invoke( + env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) + ) + } ?: 0 // @formatter:on + } + @OptIn(UnsafeJniApi::class, InternalJniApi::class) inline fun callByte( env: JniEnvironment, instance: JvmObject = JvmObject.NULL, args: ArgumentScope.() -> Unit = {} - ): Byte { - return memScoped { - when (descriptor.callType) { // @formatter:off - CallType.STATIC -> env.pointed?.CallStaticByteMethodA?.invoke( - env.ptr, enclosingClass.handle, id, allocArgs(args) - ) - CallType.VIRTUAL -> env.pointed?.CallByteMethodA?.invoke( - env.ptr, instance.handle, id, allocArgs(args) - ) - CallType.DIRECT -> env.pointed?.CallNonvirtualByteMethodA?.invoke( - env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) - ) - } ?: 0 // @formatter:on - } + ): Byte = memScoped { + when (descriptor.callType) { // @formatter:off + CallType.STATIC -> env.pointed?.CallStaticByteMethodA?.invoke( + env.ptr, enclosingClass.handle, id, allocArgs(args) + ) + CallType.VIRTUAL -> env.pointed?.CallByteMethodA?.invoke( + env.ptr, instance.handle, id, allocArgs(args) + ) + CallType.DIRECT -> env.pointed?.CallNonvirtualByteMethodA?.invoke( + env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) + ) + } ?: 0 // @formatter:on } @OptIn(UnsafeJniApi::class, InternalJniApi::class) @@ -212,20 +229,18 @@ class JvmMethod( env: JniEnvironment, instance: JvmObject = JvmObject.NULL, args: ArgumentScope.() -> Unit = {} - ): Short { - return memScoped { - when (descriptor.callType) { // @formatter:off - CallType.STATIC -> env.pointed?.CallStaticShortMethodA?.invoke( - env.ptr, enclosingClass.handle, id, allocArgs(args) - ) - CallType.VIRTUAL -> env.pointed?.CallShortMethodA?.invoke( - env.ptr, instance.handle, id, allocArgs(args) - ) - CallType.DIRECT -> env.pointed?.CallNonvirtualShortMethodA?.invoke( - env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) - ) - } ?: 0 // @formatter:on - } + ): Short = memScoped { + when (descriptor.callType) { // @formatter:off + CallType.STATIC -> env.pointed?.CallStaticShortMethodA?.invoke( + env.ptr, enclosingClass.handle, id, allocArgs(args) + ) + CallType.VIRTUAL -> env.pointed?.CallShortMethodA?.invoke( + env.ptr, instance.handle, id, allocArgs(args) + ) + CallType.DIRECT -> env.pointed?.CallNonvirtualShortMethodA?.invoke( + env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) + ) + } ?: 0 // @formatter:on } @OptIn(InternalJniApi::class, UnsafeJniApi::class) @@ -233,20 +248,18 @@ class JvmMethod( env: JniEnvironment, instance: JvmObject = JvmObject.NULL, args: ArgumentScope.() -> Unit = {} - ): Int { - return memScoped { - when (descriptor.callType) { // @formatter:off - CallType.STATIC -> env.pointed?.CallStaticIntMethodA?.invoke( - env.ptr, enclosingClass.handle, id, allocArgs(args) - ) - CallType.VIRTUAL -> env.pointed?.CallIntMethodA?.invoke( - env.ptr, instance.handle, id, allocArgs(args) - ) - CallType.DIRECT -> env.pointed?.CallNonvirtualIntMethodA?.invoke( - env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) - ) - } ?: 0 // @formatter:on - } + ): Int = memScoped { + when (descriptor.callType) { // @formatter:off + CallType.STATIC -> env.pointed?.CallStaticIntMethodA?.invoke( + env.ptr, enclosingClass.handle, id, allocArgs(args) + ) + CallType.VIRTUAL -> env.pointed?.CallIntMethodA?.invoke( + env.ptr, instance.handle, id, allocArgs(args) + ) + CallType.DIRECT -> env.pointed?.CallNonvirtualIntMethodA?.invoke( + env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) + ) + } ?: 0 // @formatter:on } @OptIn(UnsafeJniApi::class, InternalJniApi::class) @@ -254,20 +267,18 @@ class JvmMethod( env: JniEnvironment, instance: JvmObject = JvmObject.NULL, args: ArgumentScope.() -> Unit = {} - ): Long { - return memScoped { - when (descriptor.callType) { // @formatter:off - CallType.STATIC -> env.pointed?.CallStaticLongMethodA?.invoke( - env.ptr, enclosingClass.handle, id, allocArgs(args) - ) - CallType.VIRTUAL -> env.pointed?.CallLongMethodA?.invoke( - env.ptr, instance.handle, id, allocArgs(args) - ) - CallType.DIRECT -> env.pointed?.CallNonvirtualLongMethodA?.invoke( - env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) - ) - } ?: 0 // @formatter:on - } + ): Long = memScoped { + when (descriptor.callType) { // @formatter:off + CallType.STATIC -> env.pointed?.CallStaticLongMethodA?.invoke( + env.ptr, enclosingClass.handle, id, allocArgs(args) + ) + CallType.VIRTUAL -> env.pointed?.CallLongMethodA?.invoke( + env.ptr, instance.handle, id, allocArgs(args) + ) + CallType.DIRECT -> env.pointed?.CallNonvirtualLongMethodA?.invoke( + env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) + ) + } ?: 0 // @formatter:on } @OptIn(UnsafeJniApi::class, InternalJniApi::class) @@ -275,20 +286,18 @@ class JvmMethod( env: JniEnvironment, instance: JvmObject = JvmObject.NULL, args: ArgumentScope.() -> Unit = {} - ): Float { - return memScoped { - when (descriptor.callType) { // @formatter:off - CallType.STATIC -> env.pointed?.CallStaticFloatMethodA?.invoke( - env.ptr, enclosingClass.handle, id, allocArgs(args) - ) - CallType.VIRTUAL -> env.pointed?.CallFloatMethodA?.invoke( - env.ptr, instance.handle, id, allocArgs(args) - ) - CallType.DIRECT -> env.pointed?.CallNonvirtualFloatMethodA?.invoke( - env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) - ) - } ?: 0F // @formatter:on - } + ): Float = memScoped { + when (descriptor.callType) { // @formatter:off + CallType.STATIC -> env.pointed?.CallStaticFloatMethodA?.invoke( + env.ptr, enclosingClass.handle, id, allocArgs(args) + ) + CallType.VIRTUAL -> env.pointed?.CallFloatMethodA?.invoke( + env.ptr, instance.handle, id, allocArgs(args) + ) + CallType.DIRECT -> env.pointed?.CallNonvirtualFloatMethodA?.invoke( + env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) + ) + } ?: 0F // @formatter:on } @OptIn(InternalJniApi::class, UnsafeJniApi::class) @@ -296,20 +305,18 @@ class JvmMethod( env: JniEnvironment, instance: JvmObject = JvmObject.NULL, args: ArgumentScope.() -> Unit = {} - ): Double { - return memScoped { - when (descriptor.callType) { // @formatter:off - CallType.STATIC -> env.pointed?.CallStaticDoubleMethodA?.invoke( - env.ptr, enclosingClass.handle, id, allocArgs(args) - ) - CallType.VIRTUAL -> env.pointed?.CallDoubleMethodA?.invoke( - env.ptr, instance.handle, id, allocArgs(args) - ) - CallType.DIRECT -> env.pointed?.CallNonvirtualDoubleMethodA?.invoke( - env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) - ) - } ?: 0.0 // @formatter:on - } + ): Double = memScoped { + when (descriptor.callType) { // @formatter:off + CallType.STATIC -> env.pointed?.CallStaticDoubleMethodA?.invoke( + env.ptr, enclosingClass.handle, id, allocArgs(args) + ) + CallType.VIRTUAL -> env.pointed?.CallDoubleMethodA?.invoke( + env.ptr, instance.handle, id, allocArgs(args) + ) + CallType.DIRECT -> env.pointed?.CallNonvirtualDoubleMethodA?.invoke( + env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) + ) + } ?: 0.0 // @formatter:on } @OptIn(UnsafeJniApi::class, InternalJniApi::class) @@ -317,20 +324,18 @@ class JvmMethod( env: JniEnvironment, instance: JvmObject = JvmObject.NULL, args: ArgumentScope.() -> Unit = {} - ): Boolean { - return memScoped { - when (descriptor.callType) { // @formatter:off - CallType.STATIC -> env.pointed?.CallStaticBooleanMethodA?.invoke( - env.ptr, enclosingClass.handle, id, allocArgs(args) - ) - CallType.VIRTUAL -> env.pointed?.CallBooleanMethodA?.invoke( - env.ptr, instance.handle, id, allocArgs(args) - ) - CallType.DIRECT -> env.pointed?.CallNonvirtualBooleanMethodA?.invoke( - env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) - ) - }?.toKBoolean() ?: false // @formatter:on - } + ): Boolean = memScoped { + when (descriptor.callType) { // @formatter:off + CallType.STATIC -> env.pointed?.CallStaticBooleanMethodA?.invoke( + env.ptr, enclosingClass.handle, id, allocArgs(args) + ) + CallType.VIRTUAL -> env.pointed?.CallBooleanMethodA?.invoke( + env.ptr, instance.handle, id, allocArgs(args) + ) + CallType.DIRECT -> env.pointed?.CallNonvirtualBooleanMethodA?.invoke( + env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) + ) + }?.toKBoolean() ?: false // @formatter:on } @OptIn(ExperimentalNativeApi::class, UnsafeJniApi::class, InternalJniApi::class) @@ -338,22 +343,20 @@ class JvmMethod( env: JniEnvironment, instance: JvmObject = JvmObject.NULL, args: ArgumentScope.() -> Unit = {} - ): Char { - return memScoped { - // @formatter:off - Char.toChars(when (descriptor.callType) { - CallType.STATIC -> env.pointed?.CallStaticCharMethodA?.invoke( - env.ptr, enclosingClass.handle, id, allocArgs(args) - ) - CallType.VIRTUAL -> env.pointed?.CallCharMethodA?.invoke( - env.ptr, instance.handle, id, allocArgs(args) - ) - CallType.DIRECT -> env.pointed?.CallNonvirtualCharMethodA?.invoke( - env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) - ) - }?.toInt() ?: 0)[0] - // @formatter:on - } + ): Char = memScoped { + // @formatter:off + Char.toChars(when (descriptor.callType) { + CallType.STATIC -> env.pointed?.CallStaticCharMethodA?.invoke( + env.ptr, enclosingClass.handle, id, allocArgs(args) + ) + CallType.VIRTUAL -> env.pointed?.CallCharMethodA?.invoke( + env.ptr, instance.handle, id, allocArgs(args) + ) + CallType.DIRECT -> env.pointed?.CallNonvirtualCharMethodA?.invoke( + env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) + ) + }?.toInt() ?: 0)[0] + // @formatter:on } @OptIn(UnsafeJniApi::class, InternalJniApi::class) @@ -361,21 +364,20 @@ class JvmMethod( env: JniEnvironment, instance: JvmObject = JvmObject.NULL, args: ArgumentScope.() -> Unit = {} - ): JvmObject { - return memScoped { - JvmObject.fromHandle(when (descriptor.callType) { // @formatter:off - CallType.STATIC -> env.pointed?.CallStaticObjectMethodA?.invoke( - env.ptr, enclosingClass.handle, id, allocArgs(args) - ) - CallType.VIRTUAL -> env.pointed?.CallObjectMethodA?.invoke( - env.ptr, instance.handle, id, allocArgs(args) - ) - CallType.DIRECT -> env.pointed?.CallNonvirtualObjectMethodA?.invoke( - env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) - ) - } - ) // @formatter:on - } + ): JvmObject = memScoped { + // @formatter:off + JvmObject.fromHandle(when (descriptor.callType) { + CallType.STATIC -> env.pointed?.CallStaticObjectMethodA?.invoke( + env.ptr, enclosingClass.handle, id, allocArgs(args) + ) + CallType.VIRTUAL -> env.pointed?.CallObjectMethodA?.invoke( + env.ptr, instance.handle, id, allocArgs(args) + ) + CallType.DIRECT -> env.pointed?.CallNonvirtualObjectMethodA?.invoke( + env.ptr, instance.handle, enclosingClass.handle, id, allocArgs(args) + ) + }) + // @formatter:on } @OptIn(UnsafeJniApi::class) @@ -386,13 +388,13 @@ class JvmMethod( ): R = callObject(env, instance, args).uncheckedCast<R>() @OptIn(UnsafeJniApi::class) - @Suppress("IMPLICIT_CAST_TO_ANY") inline fun <reified R> call( env: JniEnvironment, instance: JvmObject = JvmObject.NULL, closure: ArgumentScope.() -> Unit = {} ): R { return when (R::class) { + Unit::class -> callVoid(env, instance, closure) Byte::class -> callByte(env, instance, closure) Short::class -> callShort(env, instance, closure) Int::class -> callInt(env, instance, closure) diff --git a/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/JvmRuntime.kt b/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/JvmRuntime.kt index 68e9824e72867552a06480cca7528c93a3a40d04..a02d8ed221e9740704f84173f9ad48fe393524c0 100644 --- a/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/JvmRuntime.kt +++ b/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/JvmRuntime.kt @@ -25,12 +25,50 @@ value class JvmRuntime @UnsafeJniApi private constructor( ) : JvmObject { companion object { @OptIn(UnsafeJniApi::class) - fun get(env: JniEnvironment): JvmRuntime? = jniScoped(env) { + fun get(env: JniEnvironment): JvmRuntime = jniScoped(env) { JvmClass.find(Type.get("java.lang.Runtime")).findMethod { name = "getRuntime" returnType = Type.get("java.lang.Runtime") callType = CallType.STATIC - }.callObject().handle?.let(::JvmRuntime) + }.callObject().handle.let { JvmRuntime(requireNotNull(it)) } } } + + fun getAvailableProcessors(env: JniEnvironment): Int = jniScoped(env) { + JvmClass.find(Type.get("java.lang.Runtime")).findMethod { + name = "availableProcessors" + returnType = PrimitiveType.INT + callType = CallType.DIRECT + }.callInt(this@JvmRuntime) + } + + fun getTotalMemory(env: JniEnvironment): Int = jniScoped { + JvmClass.find(Type.get("java.lang.Runtime")).findMethod { + name = "totalMemory" + returnType = PrimitiveType.INT + callType = CallType.DIRECT + }.callInt(this@JvmRuntime) + } + + fun getMaxMemory(env: JniEnvironment): Int = jniScoped { + JvmClass.find(Type.get("java.lang.Runtime")).findMethod { + name = "maxMemory" + returnType = PrimitiveType.INT + callType = CallType.DIRECT + }.callInt(this@JvmRuntime) + } + + fun freeMemory(env: JniEnvironment) = jniScoped(env) { + JvmClass.find(Type.get("java.lang.Runtime")).findMethod { + this.name = "freeMemory" + callType = CallType.DIRECT + }.callVoid(this@JvmRuntime) + } + + fun gc(env: JniEnvironment) = jniScoped(env) { + JvmClass.find(Type.get("java.lang.Runtime")).findMethod { + this.name = "gc" + callType = CallType.DIRECT + }.callVoid(this@JvmRuntime) + } } \ No newline at end of file diff --git a/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/VirtualMachine.kt b/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/VirtualMachine.kt index 614cd32f2c71c4de119b2ccfa727dd4b97bc12c2..6429c2db449730cc82cd42605b2fcccfd4e7962e 100644 --- a/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/VirtualMachine.kt +++ b/multiplatform-jni/src/nativeMain/kotlin/io/karma/jni/VirtualMachine.kt @@ -101,13 +101,15 @@ value class VirtualMachine private constructor( } @OptIn(UnsafeJniApi::class) - inline val environment: JniEnvironment? + inline val environment: JniEnvironment get() = memScoped { val address = allocPointerTo<JniEnvironment>() handle?.pointed?.GetEnv?.invoke(handle.ptr, interpretCPointer(address.rawPtr), 0) - address.pointed + requireNotNull(address.pointed) { "Could not retrieve environment" } } + inline fun <reified R> use(closure: JniScope.() -> R): R = jniScoped(environment, closure) + @OptIn(UnsafeJniApi::class) fun destroy() { handle?.pointed?.DestroyJavaVM?.invoke(handle.ptr)