From 8420e45e9178e34f216731d5644ca41f9b6f6884 Mon Sep 17 00:00:00 2001 From: CharlieTap Date: Sat, 7 Sep 2024 13:31:37 +0100 Subject: [PATCH] provide host functions access to module instances in their context --- .../chasm/embedding/dsl/FunctionImport.kt | 5 ---- .../chasm/embedding/dsl/HostFunction.kt | 13 +-------- ...{StoreExt.kt => HostFunctionContextExt.kt} | 28 ++++++++++--------- .../chasm/embedding/shapes/HostFunction.kt | 2 +- .../embedding/shapes/HostFunctionContext.kt | 6 ++++ .../embedding/shapes/HostFunctionFactory.kt | 3 -- .../embedding/transform/HostFunctionMapper.kt | 21 ++++++-------- .../chasm/embedding/FunctionTest.kt | 7 ++--- .../charlietap/chasm/embedding/ImportTest.kt | 7 ++--- .../invoker/function/HostFunctionCallImpl.kt | 9 +++++- .../function/HostFunctionCallImplTest.kt | 19 ++++++++++++- .../executor/runtime/instance/HostFunction.kt | 2 +- .../runtime/instance/HostFunctionContext.kt | 8 ++++++ 13 files changed, 71 insertions(+), 59 deletions(-) rename chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/ext/{StoreExt.kt => HostFunctionContextExt.kt} (67%) create mode 100644 chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/shapes/HostFunctionContext.kt delete mode 100644 chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/shapes/HostFunctionFactory.kt create mode 100644 executor/runtime/src/commonMain/kotlin/io/github/charlietap/chasm/executor/runtime/instance/HostFunctionContext.kt diff --git a/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/dsl/FunctionImport.kt b/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/dsl/FunctionImport.kt index 2f403987..430efef8 100644 --- a/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/dsl/FunctionImport.kt +++ b/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/dsl/FunctionImport.kt @@ -3,7 +3,6 @@ package io.github.charlietap.chasm.embedding.dsl import io.github.charlietap.chasm.embedding.function import io.github.charlietap.chasm.embedding.shapes.FunctionType import io.github.charlietap.chasm.embedding.shapes.HostFunction -import io.github.charlietap.chasm.embedding.shapes.HostFunctionFactory import io.github.charlietap.chasm.embedding.shapes.Import import io.github.charlietap.chasm.embedding.shapes.Store @@ -22,10 +21,6 @@ class FunctionImportBuilder(private val store: Store) { type = FunctionTypeBuilder().apply(builder).build() } - fun reference(reference: HostFunctionFactory) { - hostFunction = reference(store) - } - fun reference(reference: HostFunction) { hostFunction = reference } diff --git a/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/dsl/HostFunction.kt b/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/dsl/HostFunction.kt index 52e590ea..ca5a0b60 100644 --- a/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/dsl/HostFunction.kt +++ b/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/dsl/HostFunction.kt @@ -1,16 +1,5 @@ package io.github.charlietap.chasm.embedding.dsl import io.github.charlietap.chasm.embedding.shapes.HostFunction -import io.github.charlietap.chasm.embedding.shapes.HostFunctionFactory -import io.github.charlietap.chasm.embedding.shapes.Store -import io.github.charlietap.chasm.embedding.shapes.Value -fun hostFunction( - hostFunction: Store.(List) -> List, -): HostFunctionFactory { - return { store: Store -> - HostFunction { params -> - hostFunction(store, params) - } - } -} +fun hostFunction(function: HostFunction) = function diff --git a/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/ext/StoreExt.kt b/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/ext/HostFunctionContextExt.kt similarity index 67% rename from chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/ext/StoreExt.kt rename to chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/ext/HostFunctionContextExt.kt index f123a319..b978700c 100644 --- a/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/ext/StoreExt.kt +++ b/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/ext/HostFunctionContextExt.kt @@ -1,28 +1,30 @@ +@file:Suppress("NOTHING_TO_INLINE") + package io.github.charlietap.chasm.embedding.ext import io.github.charlietap.chasm.embedding.error.ChasmError import io.github.charlietap.chasm.embedding.memory.readByte import io.github.charlietap.chasm.embedding.memory.readBytes import io.github.charlietap.chasm.embedding.shapes.ChasmResult +import io.github.charlietap.chasm.embedding.shapes.HostFunctionContext import io.github.charlietap.chasm.embedding.shapes.Memory -import io.github.charlietap.chasm.embedding.shapes.Store import io.github.charlietap.chasm.embedding.shapes.map -fun Store.byte( +inline fun HostFunctionContext.byte( pointer: Int, memory: Memory, -): ChasmResult = readByte(this, memory, pointer) +): ChasmResult = readByte(this.store, memory, pointer) -fun Store.bytes( +inline fun HostFunctionContext.bytes( pointer: Int, numberOfBytes: Int, memory: Memory, -): ChasmResult = readBytes(this, memory, pointer, numberOfBytes) +): ChasmResult = readBytes(this.store, memory, pointer, numberOfBytes) -fun Store.int( +inline fun HostFunctionContext.int( pointer: Int, memory: Memory, -): ChasmResult = readBytes(this, memory, pointer, Int.SIZE_BYTES).map { bytes -> +): ChasmResult = readBytes(this.store, memory, pointer, Int.SIZE_BYTES).map { bytes -> var result: Int = 0 for (i in 0 until Int.SIZE_BYTES) { result = result or (bytes[i].toInt() shl Byte.SIZE_BITS * i) @@ -30,10 +32,10 @@ fun Store.int( result } -fun Store.uint( +inline fun HostFunctionContext.uint( pointer: Int, memory: Memory, -): ChasmResult = readBytes(this, memory, pointer, Int.SIZE_BYTES).map { bytes -> +): ChasmResult = readBytes(this.store, memory, pointer, Int.SIZE_BYTES).map { bytes -> var result: UInt = 0u for (i in 0 until Int.SIZE_BYTES) { result = result or (bytes[i].toUInt() shl (Byte.SIZE_BITS * i)) @@ -41,10 +43,10 @@ fun Store.uint( result } -fun Store.long( +inline fun HostFunctionContext.long( pointer: Int, memory: Memory, -): ChasmResult = readBytes(this, memory, pointer, Long.SIZE_BYTES).map { bytes -> +): ChasmResult = readBytes(this.store, memory, pointer, Long.SIZE_BYTES).map { bytes -> var result: Long = 0 for (i in 0 until Long.SIZE_BYTES) { result = result or (bytes[i].toLong() shl Byte.SIZE_BITS * i) @@ -52,10 +54,10 @@ fun Store.long( result } -fun Store.ulong( +inline fun HostFunctionContext.ulong( pointer: Int, memory: Memory, -): ChasmResult = readBytes(this, memory, pointer, Long.SIZE_BYTES).map { bytes -> +): ChasmResult = readBytes(this.store, memory, pointer, Long.SIZE_BYTES).map { bytes -> var result: ULong = 0uL for (i in 0 until Long.SIZE_BYTES) { result = result or (bytes[i].toULong() shl (Byte.SIZE_BITS * i)) diff --git a/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/shapes/HostFunction.kt b/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/shapes/HostFunction.kt index b376001e..8fbf6c03 100644 --- a/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/shapes/HostFunction.kt +++ b/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/shapes/HostFunction.kt @@ -1,3 +1,3 @@ package io.github.charlietap.chasm.embedding.shapes -fun interface HostFunction : (List) -> List +typealias HostFunction = HostFunctionContext.(List) -> List diff --git a/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/shapes/HostFunctionContext.kt b/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/shapes/HostFunctionContext.kt new file mode 100644 index 00000000..804a3b63 --- /dev/null +++ b/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/shapes/HostFunctionContext.kt @@ -0,0 +1,6 @@ +package io.github.charlietap.chasm.embedding.shapes + +data class HostFunctionContext( + val store: Store, + val instance: Instance, +) diff --git a/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/shapes/HostFunctionFactory.kt b/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/shapes/HostFunctionFactory.kt deleted file mode 100644 index 19ff914f..00000000 --- a/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/shapes/HostFunctionFactory.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.github.charlietap.chasm.embedding.shapes - -typealias HostFunctionFactory = (Store) -> HostFunction diff --git a/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/transform/HostFunctionMapper.kt b/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/transform/HostFunctionMapper.kt index 8dd23e5b..42b4cfe6 100644 --- a/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/transform/HostFunctionMapper.kt +++ b/chasm/src/commonMain/kotlin/io/github/charlietap/chasm/embedding/transform/HostFunctionMapper.kt @@ -1,29 +1,26 @@ package io.github.charlietap.chasm.embedding.transform import io.github.charlietap.chasm.embedding.shapes.HostFunction +import io.github.charlietap.chasm.embedding.shapes.HostFunctionContext +import io.github.charlietap.chasm.embedding.shapes.Instance +import io.github.charlietap.chasm.embedding.shapes.Store import io.github.charlietap.chasm.embedding.shapes.Value import io.github.charlietap.chasm.executor.runtime.value.ExecutionValue import io.github.charlietap.chasm.executor.runtime.instance.HostFunction as InternalHostFunction internal class HostFunctionMapper( private val valueMapper: BidirectionalMapper = ValueMapper.instance, -) : BidirectionalMapper { +) : Mapper { override fun map(input: HostFunction): InternalHostFunction { return { params: List -> val mappedParams = params.map(valueMapper::bimap) - val results = input(mappedParams) - results.map(valueMapper::map) - } - } - - override fun bimap(input: InternalHostFunction): HostFunction { - return object : HostFunction { - override fun invoke(params: List): List { - val mappedParams = params.map(valueMapper::map) - val results = input.invoke(mappedParams) - return results.map(valueMapper::bimap) + val store = Store(this.store) + val instance = Instance(this.instance) + val results = with(HostFunctionContext(store, instance)) { + input(mappedParams) } + results.map(valueMapper::map) } } diff --git a/chasm/src/commonTest/kotlin/io/github/charlietap/chasm/embedding/FunctionTest.kt b/chasm/src/commonTest/kotlin/io/github/charlietap/chasm/embedding/FunctionTest.kt index 654201f4..13c26871 100644 --- a/chasm/src/commonTest/kotlin/io/github/charlietap/chasm/embedding/FunctionTest.kt +++ b/chasm/src/commonTest/kotlin/io/github/charlietap/chasm/embedding/FunctionTest.kt @@ -4,7 +4,6 @@ import io.github.charlietap.chasm.embedding.fixture.publicFunction import io.github.charlietap.chasm.embedding.fixture.publicFunctionType import io.github.charlietap.chasm.embedding.fixture.publicStore import io.github.charlietap.chasm.embedding.shapes.HostFunction -import io.github.charlietap.chasm.embedding.shapes.Value import io.github.charlietap.chasm.fixture.instance.functionAddress import io.github.charlietap.chasm.fixture.instance.functionExternalValue import io.github.charlietap.chasm.fixture.type.functionType @@ -20,10 +19,8 @@ class FunctionTest { val store = publicStore() val funcType = publicFunctionType() - val hostFunction = object : HostFunction { - override fun invoke(p1: List): List { - return emptyList() - } + val hostFunction: HostFunction = { + emptyList() } val expectedType = functionType().definedType() diff --git a/chasm/src/commonTest/kotlin/io/github/charlietap/chasm/embedding/ImportTest.kt b/chasm/src/commonTest/kotlin/io/github/charlietap/chasm/embedding/ImportTest.kt index d8b97217..20656681 100644 --- a/chasm/src/commonTest/kotlin/io/github/charlietap/chasm/embedding/ImportTest.kt +++ b/chasm/src/commonTest/kotlin/io/github/charlietap/chasm/embedding/ImportTest.kt @@ -35,11 +35,8 @@ class ImportTest { emptyList(), ) - val hostFunction = object : HostFunction { - override fun invoke(p1: List): List { - println("hello") - return emptyList() - } + val hostFunction: HostFunction = { + emptyList() } val external = function(store, functionType, hostFunction) diff --git a/executor/invoker/src/commonMain/kotlin/io/github/charlietap/chasm/executor/invoker/function/HostFunctionCallImpl.kt b/executor/invoker/src/commonMain/kotlin/io/github/charlietap/chasm/executor/invoker/function/HostFunctionCallImpl.kt index 4bcf8dae..4d37f2ab 100644 --- a/executor/invoker/src/commonMain/kotlin/io/github/charlietap/chasm/executor/invoker/function/HostFunctionCallImpl.kt +++ b/executor/invoker/src/commonMain/kotlin/io/github/charlietap/chasm/executor/invoker/function/HostFunctionCallImpl.kt @@ -11,8 +11,10 @@ import io.github.charlietap.chasm.ast.type.VectorType import io.github.charlietap.chasm.executor.invoker.ext.functionType import io.github.charlietap.chasm.executor.runtime.Stack import io.github.charlietap.chasm.executor.runtime.error.InvocationError +import io.github.charlietap.chasm.executor.runtime.ext.peekFrame import io.github.charlietap.chasm.executor.runtime.ext.popValue import io.github.charlietap.chasm.executor.runtime.instance.FunctionInstance +import io.github.charlietap.chasm.executor.runtime.instance.HostFunctionContext import io.github.charlietap.chasm.executor.runtime.store.Store import io.github.charlietap.chasm.executor.runtime.value.ExecutionValue import io.github.charlietap.chasm.executor.runtime.value.NumberValue @@ -25,13 +27,18 @@ internal fun HostFunctionCallImpl( stack: Stack, function: FunctionInstance.HostFunction, ): Result = binding { + val frame = stack.peekFrame().bind() val type = function.functionType().bind() val params = List(type.params.types.size) { stack.popValue().bind().value }.asReversed() - val results = function.function.invoke(params) + val functionContext = HostFunctionContext( + store, + frame.state.module, + ) + val results = function.function.invoke(functionContext, params) type.results.types.forEachIndexed { index, valueType -> val result = results.getOrNull(index) diff --git a/executor/invoker/src/commonTest/kotlin/io/github/charlietap/chasm/executor/invoker/function/HostFunctionCallImplTest.kt b/executor/invoker/src/commonTest/kotlin/io/github/charlietap/chasm/executor/invoker/function/HostFunctionCallImplTest.kt index 186a70b9..c15e7762 100644 --- a/executor/invoker/src/commonTest/kotlin/io/github/charlietap/chasm/executor/invoker/function/HostFunctionCallImplTest.kt +++ b/executor/invoker/src/commonTest/kotlin/io/github/charlietap/chasm/executor/invoker/function/HostFunctionCallImplTest.kt @@ -6,6 +6,9 @@ import io.github.charlietap.chasm.executor.runtime.Stack import io.github.charlietap.chasm.executor.runtime.error.InvocationError import io.github.charlietap.chasm.executor.runtime.instance.FunctionInstance import io.github.charlietap.chasm.executor.runtime.instance.HostFunction +import io.github.charlietap.chasm.fixture.frame +import io.github.charlietap.chasm.fixture.frameState +import io.github.charlietap.chasm.fixture.instance.moduleInstance import io.github.charlietap.chasm.fixture.stack import io.github.charlietap.chasm.fixture.store import io.github.charlietap.chasm.fixture.type.functionType @@ -25,6 +28,13 @@ class HostFunctionCallImplTest { val store = store() val stack = stack() + val frame = frame( + state = frameState( + moduleInstance = moduleInstance(), + ), + ) + + stack.push(frame) val functionType = functionType( params = resultType( @@ -70,7 +80,7 @@ class HostFunctionCallImplTest { ) assertEquals(Ok(Unit), actual) - assertEquals(0, stack.framesDepth()) + assertEquals(1, stack.framesDepth()) assertEquals(2, stack.valuesDepth()) assertEquals(i64(118), stack.popValueOrNull()?.value) assertEquals(i32(117), stack.popValueOrNull()?.value) @@ -81,6 +91,13 @@ class HostFunctionCallImplTest { val store = store() val stack = stack() + val frame = frame( + state = frameState( + moduleInstance = moduleInstance(), + ), + ) + + stack.push(frame) val functionType = functionType( params = resultType( diff --git a/executor/runtime/src/commonMain/kotlin/io/github/charlietap/chasm/executor/runtime/instance/HostFunction.kt b/executor/runtime/src/commonMain/kotlin/io/github/charlietap/chasm/executor/runtime/instance/HostFunction.kt index 39425113..8c049277 100644 --- a/executor/runtime/src/commonMain/kotlin/io/github/charlietap/chasm/executor/runtime/instance/HostFunction.kt +++ b/executor/runtime/src/commonMain/kotlin/io/github/charlietap/chasm/executor/runtime/instance/HostFunction.kt @@ -2,4 +2,4 @@ package io.github.charlietap.chasm.executor.runtime.instance import io.github.charlietap.chasm.executor.runtime.value.ExecutionValue -typealias HostFunction = (List) -> List +typealias HostFunction = HostFunctionContext.(List) -> List diff --git a/executor/runtime/src/commonMain/kotlin/io/github/charlietap/chasm/executor/runtime/instance/HostFunctionContext.kt b/executor/runtime/src/commonMain/kotlin/io/github/charlietap/chasm/executor/runtime/instance/HostFunctionContext.kt new file mode 100644 index 00000000..bdf31c93 --- /dev/null +++ b/executor/runtime/src/commonMain/kotlin/io/github/charlietap/chasm/executor/runtime/instance/HostFunctionContext.kt @@ -0,0 +1,8 @@ +package io.github.charlietap.chasm.executor.runtime.instance + +import io.github.charlietap.chasm.executor.runtime.store.Store + +data class HostFunctionContext( + val store: Store, + val instance: ModuleInstance, +)