diff --git a/executor/invoker/src/commonMain/kotlin/io/github/charlietap/chasm/executor/invoker/dispatch/referencefused/RefTestDispatcher.kt b/executor/invoker/src/commonMain/kotlin/io/github/charlietap/chasm/executor/invoker/dispatch/referencefused/RefTestDispatcher.kt new file mode 100644 index 00000000..e631b12d --- /dev/null +++ b/executor/invoker/src/commonMain/kotlin/io/github/charlietap/chasm/executor/invoker/dispatch/referencefused/RefTestDispatcher.kt @@ -0,0 +1,20 @@ +package io.github.charlietap.chasm.executor.invoker.dispatch.referencefused + +import io.github.charlietap.chasm.executor.invoker.instruction.referencefused.RefTestExecutor +import io.github.charlietap.chasm.executor.runtime.dispatch.DispatchableInstruction +import io.github.charlietap.chasm.executor.runtime.execution.Executor +import io.github.charlietap.chasm.executor.runtime.instruction.FusedReferenceInstruction + +fun RefTestDispatcher( + instruction: FusedReferenceInstruction.RefTest, +) = RefTestDispatcher( + instruction = instruction, + executor = ::RefTestExecutor, +) + +internal inline fun RefTestDispatcher( + instruction: FusedReferenceInstruction.RefTest, + crossinline executor: Executor, +): DispatchableInstruction = { context -> + executor(context, instruction) +} diff --git a/executor/invoker/src/commonMain/kotlin/io/github/charlietap/chasm/executor/invoker/instruction/referencefused/RefTestExecutor.kt b/executor/invoker/src/commonMain/kotlin/io/github/charlietap/chasm/executor/invoker/instruction/referencefused/RefTestExecutor.kt new file mode 100644 index 00000000..232128af --- /dev/null +++ b/executor/invoker/src/commonMain/kotlin/io/github/charlietap/chasm/executor/invoker/instruction/referencefused/RefTestExecutor.kt @@ -0,0 +1,38 @@ +package io.github.charlietap.chasm.executor.invoker.instruction.referencefused + +import io.github.charlietap.chasm.executor.invoker.type.TypeOf +import io.github.charlietap.chasm.executor.invoker.type.TypeOfReferenceValue +import io.github.charlietap.chasm.executor.runtime.execution.ExecutionContext +import io.github.charlietap.chasm.executor.runtime.instruction.FusedReferenceInstruction +import io.github.charlietap.chasm.type.ReferenceType +import io.github.charlietap.chasm.type.matching.ReferenceTypeMatcher +import io.github.charlietap.chasm.type.matching.TypeMatcher + +internal fun RefTestExecutor( + context: ExecutionContext, + instruction: FusedReferenceInstruction.RefTest, +) = RefTestExecutor( + context = context, + instruction = instruction, + referenceTypeMatcher = ::ReferenceTypeMatcher, + typeOfReferenceValue = ::TypeOfReferenceValue, +) + +internal inline fun RefTestExecutor( + context: ExecutionContext, + instruction: FusedReferenceInstruction.RefTest, + crossinline referenceTypeMatcher: TypeMatcher, + crossinline typeOfReferenceValue: TypeOf, +) { + val stack = context.vstack + val store = context.store + val frame = context.cstack.peekFrame() + val moduleInstance = frame.instance + + val referenceType = typeOfReferenceValue(instruction.reference(stack), store, moduleInstance) + if (referenceTypeMatcher(referenceType, instruction.referenceType, context)) { + instruction.destination(1L, stack) + } else { + instruction.destination(0L, stack) + } +} diff --git a/executor/runtime-internal/src/commonMain/kotlin/io/github/charlietap/chasm/executor/runtime/instruction/FusedReferenceInstruction.kt b/executor/runtime-internal/src/commonMain/kotlin/io/github/charlietap/chasm/executor/runtime/instruction/FusedReferenceInstruction.kt index 72f08020..89f3b8e9 100644 --- a/executor/runtime-internal/src/commonMain/kotlin/io/github/charlietap/chasm/executor/runtime/instruction/FusedReferenceInstruction.kt +++ b/executor/runtime-internal/src/commonMain/kotlin/io/github/charlietap/chasm/executor/runtime/instruction/FusedReferenceInstruction.kt @@ -1,5 +1,7 @@ package io.github.charlietap.chasm.executor.runtime.instruction +import io.github.charlietap.chasm.type.ReferenceType + sealed interface FusedReferenceInstruction : LinkedInstruction { data class RefEq( @@ -17,4 +19,10 @@ sealed interface FusedReferenceInstruction : LinkedInstruction { val destination: StoreOp, val reference: Long, ) : FusedReferenceInstruction + + data class RefTest( + val reference: LoadOp, + val destination: StoreOp, + val referenceType: ReferenceType, + ) : FusedReferenceInstruction } diff --git a/ir/src/commonMain/kotlin/io/github/charlietap/chasm/ir/instruction/FusedReferenceInstruction.kt b/ir/src/commonMain/kotlin/io/github/charlietap/chasm/ir/instruction/FusedReferenceInstruction.kt index 3fe53460..90896557 100644 --- a/ir/src/commonMain/kotlin/io/github/charlietap/chasm/ir/instruction/FusedReferenceInstruction.kt +++ b/ir/src/commonMain/kotlin/io/github/charlietap/chasm/ir/instruction/FusedReferenceInstruction.kt @@ -1,6 +1,7 @@ package io.github.charlietap.chasm.ir.instruction import io.github.charlietap.chasm.type.HeapType +import io.github.charlietap.chasm.type.ReferenceType sealed interface FusedReferenceInstruction : Instruction { @@ -19,4 +20,10 @@ sealed interface FusedReferenceInstruction : Instruction { val destination: FusedDestination, val type: HeapType, ) : FusedReferenceInstruction + + data class RefTest( + val reference: FusedOperand, + val destination: FusedDestination, + val referenceType: ReferenceType, + ) : FusedReferenceInstruction } diff --git a/optimiser/src/commonMain/kotlin/io/github/charlietap/chasm/optimiser/passes/fusion/ReferenceInstructionFuser.kt b/optimiser/src/commonMain/kotlin/io/github/charlietap/chasm/optimiser/passes/fusion/ReferenceInstructionFuser.kt index 1360ce09..2845154e 100644 --- a/optimiser/src/commonMain/kotlin/io/github/charlietap/chasm/optimiser/passes/fusion/ReferenceInstructionFuser.kt +++ b/optimiser/src/commonMain/kotlin/io/github/charlietap/chasm/optimiser/passes/fusion/ReferenceInstructionFuser.kt @@ -131,6 +131,40 @@ internal inline fun ReferenceInstructionFuser( nextIndex } + is ReferenceInstruction.RefTest -> { + var nextIndex = index + + val reference = input.getOrNull(index - 1)?.let(operandFactory) + val destination = input.getOrNull(index + 1).let(destinationFactory) + + val instruction = if (reference == null && destination == FusedDestination.ValueStack) { + instruction + } else { + when { + reference == null -> FusedReferenceInstruction.RefTest( + reference = FusedOperand.ValueStack, + destination = destination, + referenceType = instruction.referenceType, + ) + else -> { + output.removeLast() + FusedReferenceInstruction.RefTest( + reference = reference, + destination = destination, + referenceType = instruction.referenceType, + ) + } + } + } + + output.add(instruction) + + if (destination != FusedDestination.ValueStack) { + nextIndex++ + } + + nextIndex + } else -> { output.add(instruction) index diff --git a/predecoder/src/commonMain/kotlin/io/github/charlietap/chasm/predecoder/instruction/referencefused/FusedReferenceInstructionPredecoder.kt b/predecoder/src/commonMain/kotlin/io/github/charlietap/chasm/predecoder/instruction/referencefused/FusedReferenceInstructionPredecoder.kt index 8b6e70fb..ddbac522 100644 --- a/predecoder/src/commonMain/kotlin/io/github/charlietap/chasm/predecoder/instruction/referencefused/FusedReferenceInstructionPredecoder.kt +++ b/predecoder/src/commonMain/kotlin/io/github/charlietap/chasm/predecoder/instruction/referencefused/FusedReferenceInstructionPredecoder.kt @@ -6,12 +6,14 @@ import io.github.charlietap.chasm.executor.invoker.dispatch.Dispatcher import io.github.charlietap.chasm.executor.invoker.dispatch.referencefused.RefEqDispatcher import io.github.charlietap.chasm.executor.invoker.dispatch.referencefused.RefIsNullDispatcher import io.github.charlietap.chasm.executor.invoker.dispatch.referencefused.RefNullDispatcher +import io.github.charlietap.chasm.executor.invoker.dispatch.referencefused.RefTestDispatcher import io.github.charlietap.chasm.executor.runtime.dispatch.DispatchableInstruction import io.github.charlietap.chasm.executor.runtime.error.ModuleTrapError import io.github.charlietap.chasm.executor.runtime.ext.toLong import io.github.charlietap.chasm.executor.runtime.instruction.FusedReferenceInstruction.RefEq import io.github.charlietap.chasm.executor.runtime.instruction.FusedReferenceInstruction.RefIsNull import io.github.charlietap.chasm.executor.runtime.instruction.FusedReferenceInstruction.RefNull +import io.github.charlietap.chasm.executor.runtime.instruction.FusedReferenceInstruction.RefTest import io.github.charlietap.chasm.executor.runtime.value.ReferenceValue import io.github.charlietap.chasm.ir.instruction.FusedReferenceInstruction import io.github.charlietap.chasm.predecoder.LoadFactory @@ -30,6 +32,7 @@ internal fun FusedReferenceInstructionPredecoder( refEqDispatcher = ::RefEqDispatcher, refIsNullDispatcher = ::RefIsNullDispatcher, refNullDispatcher = ::RefNullDispatcher, + refTestDispatcher = ::RefTestDispatcher, ) internal inline fun FusedReferenceInstructionPredecoder( @@ -40,6 +43,7 @@ internal inline fun FusedReferenceInstructionPredecoder( crossinline refEqDispatcher: Dispatcher, crossinline refIsNullDispatcher: Dispatcher, crossinline refNullDispatcher: Dispatcher, + crossinline refTestDispatcher: Dispatcher, ): Result = binding { when (instruction) { is FusedReferenceInstruction.RefEq -> { @@ -72,5 +76,17 @@ internal inline fun FusedReferenceInstructionPredecoder( val reference = ReferenceValue.Null(instruction.type).toLong() refNullDispatcher(RefNull(destination, reference)) } + is FusedReferenceInstruction.RefTest -> { + val reference = loadFactory(context, instruction.reference) + val destination = storeFactory(context, instruction.destination) + + refTestDispatcher( + RefTest( + reference = reference, + destination = destination, + referenceType = instruction.referenceType, + ), + ) + } } }