summary refs log tree commit diff stats
path: root/src/main/kotlin/space/autistic/radio/wasm
diff options
context:
space:
mode:
authorSoniEx2 <endermoneymod@gmail.com>2025-03-15 18:57:24 -0300
committerSoniEx2 <endermoneymod@gmail.com>2025-03-15 18:57:24 -0300
commit2aa1dea5126290ee6dadc0884a3d8e2791be04ef (patch)
tree0e488cfbf8bd6337fd194b1b6a467e2172e5ac54 /src/main/kotlin/space/autistic/radio/wasm
parentfee7157d84c3ce887a540be82dc7a7d2e0c8e368 (diff)
add everything so far
Diffstat (limited to 'src/main/kotlin/space/autistic/radio/wasm')
-rw-r--r--src/main/kotlin/space/autistic/radio/wasm/Bindings.kt173
1 files changed, 173 insertions, 0 deletions
diff --git a/src/main/kotlin/space/autistic/radio/wasm/Bindings.kt b/src/main/kotlin/space/autistic/radio/wasm/Bindings.kt
new file mode 100644
index 0000000..cc123a1
--- /dev/null
+++ b/src/main/kotlin/space/autistic/radio/wasm/Bindings.kt
@@ -0,0 +1,173 @@
+package space.autistic.radio.wasm
+
+import com.dylibso.chicory.runtime.HostFunction
+import com.dylibso.chicory.runtime.ImportFunction
+import com.dylibso.chicory.runtime.Instance
+import com.dylibso.chicory.wasm.types.Value
+import com.dylibso.chicory.wasm.types.ValueType
+import java.lang.invoke.MethodHandles
+import java.lang.invoke.MethodType
+import java.lang.reflect.Method
+import java.lang.reflect.ParameterizedType
+
+class Bindings {
+
+    companion object {
+        @JvmStatic
+        fun longToInt(long: Long): Int = long.toInt()
+
+        @JvmStatic
+        fun stringArg(instance: Instance, address: Long): String {
+            return instance.memory().readCString(address.toInt())
+        }
+
+        @JvmStatic
+        fun boolArg(bool: Long): Boolean {
+            return bool != 0L
+        }
+
+        @JvmStatic
+        fun intListArg(instance: Instance, argc: Long, argv: Long): List<Int> {
+            return IntArray(argc.toInt()) {
+                instance.memory().readInt(argv.toInt() + 4 * it)
+            }.toList()
+        }
+
+        private val lookup = MethodHandles.lookup()
+        fun bindFunc(
+            module: String,
+            name: String,
+            inLookup: MethodHandles.Lookup,
+            method: Method,
+            receiver: Any
+        ): ImportFunction {
+            val baseHandle = inLookup.unreflect(method).bindTo(receiver)
+            val wasmParameters = ArrayList<ValueType>()
+            val filters = method.genericParameterTypes.map {
+                when (it) {
+                    Int::class.java -> {
+                        wasmParameters.add(ValueType.I32)
+                        lookup.findStatic(
+                            Bindings::class.java, "longToInt", MethodType.methodType(Int::class.java, Long::class.java)
+                        )
+                    }
+
+                    Long::class.java -> {
+                        wasmParameters.add(ValueType.I64)
+                        MethodHandles.identity(Long::class.java)
+                    }
+
+                    Float::class.java -> {
+                        wasmParameters.add(ValueType.F32)
+                        lookup.findStatic(
+                            Value::class.java, "longToFloat", MethodType.methodType(Float::class.java, Long::class.java)
+                        )
+                    }
+
+                    Double::class.java -> {
+                        wasmParameters.add(ValueType.F64)
+                        lookup.findStatic(
+                            Value::class.java,
+                            "longToDouble",
+                            MethodType.methodType(Double::class.java, Long::class.java)
+                        )
+                    }
+
+                    String::class.java -> {
+                        wasmParameters.add(ValueType.I32)
+                        lookup.findStatic(
+                            Bindings::class.java,
+                            "stringArg",
+                            MethodType.methodType(String::class.java, Instance::class.java, Long::class.java)
+                        )
+                    }
+
+                    Boolean::class.java -> {
+                        wasmParameters.add(ValueType.I32)
+                        lookup.findStatic(
+                            Bindings::class.java,
+                            "boolArg",
+                            MethodType.methodType(Boolean::class.java, Long::class.java)
+                        )
+                    }
+
+                    is ParameterizedType -> {
+                        if (it.rawType == List::class.java) {
+                            val converter = when (it.actualTypeArguments[0]) {
+                                java.lang.Integer::class.java -> "intListArg"
+                                else -> throw IllegalArgumentException(it.actualTypeArguments[0].toString())
+                            }
+                            wasmParameters.add(ValueType.I32)
+                            wasmParameters.add(ValueType.I32)
+                            lookup.findStatic(
+                                Bindings::class.java,
+                                converter,
+                                MethodType.methodType(
+                                    List::class.java,
+                                    Instance::class.java,
+                                    Long::class.java,
+                                    Long::class.java
+                                )
+                            )
+                        } else {
+                            throw IllegalArgumentException(it.toString())
+                        }
+                    }
+
+                    else -> throw IllegalArgumentException(it.toString())
+                }
+            }
+            val filterTypes = ArrayList<Class<*>>()
+            filters.forEach { methodHandle ->
+                filterTypes.addAll(methodHandle.type().parameterList())
+            }
+            var i = 0
+            val permutation = IntArray(filterTypes.size) {
+                if (filterTypes[it] == Instance::class.java) 0 else ++i
+            }
+            var handle = baseHandle
+            var j = 0
+            filters.forEach {
+                handle = MethodHandles.collectArguments(handle, j, it)
+                j += it.type().parameterCount()
+            }
+            val newtype = MethodType.methodType(
+                baseHandle.type().returnType(), Instance::class.java, *Array(i) { Long::class.java })
+            handle = MethodHandles.permuteArguments(handle, newtype, *permutation)
+            handle = handle.asSpreader(LongArray::class.java, i)
+            return when (method.genericReturnType) {
+                Void.TYPE -> HostFunction(module, name, wasmParameters, emptyList()) { instance, args ->
+                    handle.invokeExact(instance, args)
+                    Value.EMPTY_VALUES
+                }
+
+                Int::class.java -> HostFunction(module, name, wasmParameters, listOf(ValueType.I32)) { instance, args ->
+                    val result: Int = handle.invokeExact(instance, args) as Int
+                    longArrayOf(result.toLong())
+                }
+
+                Boolean::class.java -> HostFunction(
+                    module,
+                    name,
+                    wasmParameters,
+                    listOf(ValueType.I32)
+                ) { instance, args ->
+                    val result: Boolean = handle.invokeExact(instance, args) as Boolean
+                    longArrayOf(if (result) 1L else 0L)
+                }
+
+                Float::class.java -> HostFunction(
+                    module,
+                    name,
+                    wasmParameters,
+                    listOf(ValueType.F32)
+                ) { instance, args ->
+                    val result: Float = handle.invokeExact(instance, args) as Float
+                    longArrayOf(Value.floatToLong(result))
+                }
+
+                else -> throw IllegalArgumentException(method.genericReturnType.toString())
+            }
+        }
+    }
+}
\ No newline at end of file