Skip to content

Commit

Permalink
Kotlin: Switch to JNA direct mapping
Browse files Browse the repository at this point in the history
According to https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md
direct mapping can improve performance substantially, maybe even that of custom JNI.
Given we know all methods it's easy to switch it all over.

Note that I have not run any actual benchmark to see how it helps.
  • Loading branch information
badboy committed Sep 2, 2024
1 parent 74c065a commit 21991c5
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 31 deletions.
8 changes: 3 additions & 5 deletions uniffi_bindgen/src/bindings/kotlin/gen_kotlin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ mod filters {
) -> Result<String, askama::Error> {
let ffi_func = callable.ffi_rust_future_poll(ci);
Ok(format!(
"{{ future, callback, continuation -> UniffiLib.INSTANCE.{ffi_func}(future, callback, continuation) }}"
"{{ future, callback, continuation -> UniffiLib.{ffi_func}(future, callback, continuation) }}"
))
}

Expand All @@ -678,7 +678,7 @@ mod filters {
ci: &ComponentInterface,
) -> Result<String, askama::Error> {
let ffi_func = callable.ffi_rust_future_complete(ci);
let call = format!("UniffiLib.INSTANCE.{ffi_func}(future, continuation)");
let call = format!("UniffiLib.{ffi_func}(future, continuation)");
let call = match callable.return_type() {
Some(Type::External {
kind: ExternalKind::DataClass,
Expand All @@ -699,9 +699,7 @@ mod filters {
ci: &ComponentInterface,
) -> Result<String, askama::Error> {
let ffi_func = callable.ffi_rust_future_free(ci);
Ok(format!(
"{{ future -> UniffiLib.INSTANCE.{ffi_func}(future) }}"
))
Ok(format!("{{ future -> UniffiLib.{ffi_func}(future) }}"))
}

/// Remove the "`" chars we put around function/variable names
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,28 +59,25 @@ internal open class {{ ffi_struct.name()|ffi_struct_name }}(
// A JNA Library to expose the extern-C FFI definitions.
// This is an implementation detail which will be called internally by the public API.

internal interface UniffiLib : Library {
companion object {
internal val INSTANCE: UniffiLib by lazy {
loadIndirect<UniffiLib>(componentName = "{{ ci.namespace() }}")
.also { lib: UniffiLib ->
uniffiCheckContractApiVersion(lib)
uniffiCheckApiChecksums(lib)
{% for fn in self.initialization_fns() -%}
{{ fn }}(lib)
{% endfor -%}
}
}
{% if ci.contains_object_types() %}
// The Cleaner for the whole library
internal val CLEANER: UniffiCleaner by lazy {
UniffiCleaner.create()
}
{%- endif %}
internal object UniffiLib {
{% if ci.contains_object_types() %}
// The Cleaner for the whole library
internal val CLEANER: UniffiCleaner by lazy {
UniffiCleaner.create()
}
{% endif %}

init {
Native.register(findLibraryName(componentName = "{{ ci.namespace() }}"))
uniffiCheckContractApiVersion(this)
uniffiCheckApiChecksums(this)
{% for fn in self.initialization_fns() -%}
{{ fn }}(this)
{% endfor %}
}

{% for func in ci.iter_ffi_function_definitions() -%}
fun {{ func.name() }}(
@JvmStatic external fun {{ func.name() }}(
{%- call kt::arg_list_ffi_decl(func) %}
): {% match func.return_type() %}{% when Some with (return_type) %}{{ return_type.borrow()|ffi_type_name_by_value }}{% when None %}Unit{% endmatch %}
{% endfor %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,15 @@ open class {{ impl_class_name }}: Disposable, AutoCloseable, {{ interface_name }
override fun run() {
pointer?.let { ptr ->
uniffiRustCall { status ->
UniffiLib.INSTANCE.{{ obj.ffi_object_free().name() }}(ptr, status)
UniffiLib.{{ obj.ffi_object_free().name() }}(ptr, status)
}
}
}
}

fun uniffiClonePointer(): Pointer {
return uniffiRustCall() { status ->
UniffiLib.INSTANCE.{{ obj.ffi_object_clone().name() }}(pointer!!, status)
UniffiLib.{{ obj.ffi_object_clone().name() }}(pointer!!, status)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ open class RustBuffer : Structure() {
companion object {
internal fun alloc(size: ULong = 0UL) = uniffiRustCall() { status ->
// Note: need to convert the size to a `Long` value to make this work with JVM.
UniffiLib.INSTANCE.{{ ci.ffi_rustbuffer_alloc().name() }}(size.toLong(), status)
UniffiLib.{{ ci.ffi_rustbuffer_alloc().name() }}(size.toLong(), status)
}.also {
if(it.data == null) {
throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})")
Expand All @@ -38,7 +38,7 @@ open class RustBuffer : Structure() {
}

internal fun free(buf: RustBuffer.ByValue) = uniffiRustCall() { status ->
UniffiLib.INSTANCE.{{ ci.ffi_rustbuffer_free().name() }}(buf, status)
UniffiLib.{{ ci.ffi_rustbuffer_free().name() }}(buf, status)
}
}

Expand Down
6 changes: 3 additions & 3 deletions uniffi_bindgen/src/bindings/kotlin/templates/macros.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
{%- else %}
uniffiRustCall()
{%- endmatch %} { _status ->
UniffiLib.INSTANCE.{{ func.ffi_func().name() }}(
UniffiLib.{{ func.ffi_func().name() }}(
{% if func.takes_self() %}it, {% endif -%}
{% call arg_list_lowered(func) -%}
_status)
Expand Down Expand Up @@ -60,13 +60,13 @@
uniffiRustCallAsync(
{%- if callable.takes_self() %}
callWithPointer { thisPtr ->
UniffiLib.INSTANCE.{{ callable.ffi_func().name() }}(
UniffiLib.{{ callable.ffi_func().name() }}(
thisPtr,
{% call arg_list_lowered(callable) %}
)
},
{%- else %}
UniffiLib.INSTANCE.{{ callable.ffi_func().name() }}({% call arg_list_lowered(callable) %}),
UniffiLib.{{ callable.ffi_func().name() }}({% call arg_list_lowered(callable) %}),
{%- endif %}
{{ callable|async_poll(ci) }},
{{ callable|async_complete(ci) }},
Expand Down

0 comments on commit 21991c5

Please sign in to comment.