Skip to content

Commit

Permalink
provide host functions access to module instances in their context
Browse files Browse the repository at this point in the history
  • Loading branch information
CharlieTap committed Sep 7, 2024
1 parent b3a86dd commit 8420e45
Show file tree
Hide file tree
Showing 13 changed files with 71 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Value>) -> List<Value>,
): HostFunctionFactory {
return { store: Store ->
HostFunction { params ->
hostFunction(store, params)
}
}
}
fun hostFunction(function: HostFunction) = function
Original file line number Diff line number Diff line change
@@ -1,61 +1,63 @@
@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<Byte, ChasmError.ExecutionError> = readByte(this, memory, pointer)
): ChasmResult<Byte, ChasmError.ExecutionError> = readByte(this.store, memory, pointer)

fun Store.bytes(
inline fun HostFunctionContext.bytes(
pointer: Int,
numberOfBytes: Int,
memory: Memory,
): ChasmResult<ByteArray, ChasmError.ExecutionError> = readBytes(this, memory, pointer, numberOfBytes)
): ChasmResult<ByteArray, ChasmError.ExecutionError> = readBytes(this.store, memory, pointer, numberOfBytes)

fun Store.int(
inline fun HostFunctionContext.int(
pointer: Int,
memory: Memory,
): ChasmResult<Int, ChasmError.ExecutionError> = readBytes(this, memory, pointer, Int.SIZE_BYTES).map { bytes ->
): ChasmResult<Int, ChasmError.ExecutionError> = 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)
}
result
}

fun Store.uint(
inline fun HostFunctionContext.uint(
pointer: Int,
memory: Memory,
): ChasmResult<UInt, ChasmError.ExecutionError> = readBytes(this, memory, pointer, Int.SIZE_BYTES).map { bytes ->
): ChasmResult<UInt, ChasmError.ExecutionError> = 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))
}
result
}

fun Store.long(
inline fun HostFunctionContext.long(
pointer: Int,
memory: Memory,
): ChasmResult<Long, ChasmError.ExecutionError> = readBytes(this, memory, pointer, Long.SIZE_BYTES).map { bytes ->
): ChasmResult<Long, ChasmError.ExecutionError> = 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)
}
result
}

fun Store.ulong(
inline fun HostFunctionContext.ulong(
pointer: Int,
memory: Memory,
): ChasmResult<ULong, ChasmError.ExecutionError> = readBytes(this, memory, pointer, Long.SIZE_BYTES).map { bytes ->
): ChasmResult<ULong, ChasmError.ExecutionError> = 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))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package io.github.charlietap.chasm.embedding.shapes

fun interface HostFunction : (List<Value>) -> List<Value>
typealias HostFunction = HostFunctionContext.(List<Value>) -> List<Value>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.github.charlietap.chasm.embedding.shapes

data class HostFunctionContext(
val store: Store,
val instance: Instance,
)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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<Value, ExecutionValue> = ValueMapper.instance,
) : BidirectionalMapper<HostFunction, InternalHostFunction> {
) : Mapper<HostFunction, InternalHostFunction> {

override fun map(input: HostFunction): InternalHostFunction {
return { params: List<ExecutionValue> ->
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<Value>): List<Value> {
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)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -20,10 +19,8 @@ class FunctionTest {

val store = publicStore()
val funcType = publicFunctionType()
val hostFunction = object : HostFunction {
override fun invoke(p1: List<Value>): List<Value> {
return emptyList()
}
val hostFunction: HostFunction = {
emptyList()
}

val expectedType = functionType().definedType()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,8 @@ class ImportTest {
emptyList(),
)

val hostFunction = object : HostFunction {
override fun invoke(p1: List<Value>): List<Value> {
println("hello")
return emptyList()
}
val hostFunction: HostFunction = {
emptyList()
}

val external = function(store, functionType, hostFunction)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -25,13 +27,18 @@ internal fun HostFunctionCallImpl(
stack: Stack,
function: FunctionInstance.HostFunction,
): Result<Unit, InvocationError> = 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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(
Expand Down Expand Up @@ -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)
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ package io.github.charlietap.chasm.executor.runtime.instance

import io.github.charlietap.chasm.executor.runtime.value.ExecutionValue

typealias HostFunction = (List<ExecutionValue>) -> List<ExecutionValue>
typealias HostFunction = HostFunctionContext.(List<ExecutionValue>) -> List<ExecutionValue>
Original file line number Diff line number Diff line change
@@ -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,
)

0 comments on commit 8420e45

Please sign in to comment.