From 2aa1dea5126290ee6dadc0884a3d8e2791be04ef Mon Sep 17 00:00:00 2001 From: SoniEx2 Date: Sat, 15 Mar 2025 18:57:24 -0300 Subject: add everything so far --- .../kotlin/space/autistic/radio/wasm/Bindings.kt | 173 +++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 src/main/kotlin/space/autistic/radio/wasm/Bindings.kt (limited to 'src/main/kotlin/space/autistic/radio/wasm') 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 { + 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() + 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>() + 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 -- cgit 1.4.1