Skip to content

Commit

Permalink
refeq bytecode fusion
Browse files Browse the repository at this point in the history
  • Loading branch information
CharlieTap committed Feb 27, 2025
1 parent f5ec519 commit c52b1fe
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.charlietap.chasm.executor.invoker.dispatch.referencefused

import io.github.charlietap.chasm.executor.invoker.instruction.referencefused.RefEqExecutor
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 RefEqDispatcher(
instruction: FusedReferenceInstruction.RefEq,
) = RefEqDispatcher(
instruction = instruction,
executor = ::RefEqExecutor,
)

internal inline fun RefEqDispatcher(
instruction: FusedReferenceInstruction.RefEq,
crossinline executor: Executor<FusedReferenceInstruction.RefEq>,
): DispatchableInstruction = { context ->
executor(context, instruction)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.github.charlietap.chasm.executor.invoker.instruction.referencefused

import io.github.charlietap.chasm.executor.runtime.execution.ExecutionContext
import io.github.charlietap.chasm.executor.runtime.ext.isNullableReference
import io.github.charlietap.chasm.executor.runtime.instruction.FusedReferenceInstruction

internal inline fun RefEqExecutor(
context: ExecutionContext,
instruction: FusedReferenceInstruction.RefEq,
) {
val stack = context.vstack

val reference1 = instruction.reference1(stack)
val reference2 = instruction.reference2(stack)

val bothTypesAreNull = reference1.isNullableReference() && reference2.isNullableReference()
if (bothTypesAreNull || reference1 == reference2) {
instruction.destination(1L, stack)
} else {
instruction.destination(0L, stack)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ package io.github.charlietap.chasm.executor.runtime.instruction

sealed interface FusedReferenceInstruction : LinkedInstruction {

data class RefEq(
val reference1: LoadOp,
val reference2: LoadOp,
val destination: StoreOp,
) : FusedReferenceInstruction

data class RefIsNull(
val value: LoadOp,
val destination: StoreOp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import io.github.charlietap.chasm.type.HeapType

sealed interface FusedReferenceInstruction : Instruction {

data class RefEq(
val reference1: FusedOperand,
val reference2: FusedOperand,
val destination: FusedDestination,
) : FusedReferenceInstruction

data class RefIsNull(
val value: FusedOperand,
val destination: FusedDestination,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,50 @@ internal inline fun ReferenceInstructionFuser(
operandFactory: FusedOperandFactory,
destinationFactory: FusedDestinationFactory,
): Int = when (instruction) {
is ReferenceInstruction.RefEq -> {
var nextIndex = index

val reference1 = input.getOrNull(index - 1)?.let(operandFactory)
val reference2 = input.getOrNull(index - 2)?.let(operandFactory)
val destination = input.getOrNull(index + 1).let(destinationFactory)

val instruction = if (reference1 == null && destination == FusedDestination.ValueStack) {
instruction
} else {
when {
reference1 == null -> FusedReferenceInstruction.RefEq(
reference1 = FusedOperand.ValueStack,
reference2 = FusedOperand.ValueStack,
destination = destination,
)
reference2 == null -> {
output.removeLast()
FusedReferenceInstruction.RefEq(
reference1 = reference1,
reference2 = FusedOperand.ValueStack,
destination = destination,
)
}
else -> {
output.removeLast()
output.removeLast()
FusedReferenceInstruction.RefEq(
reference1 = reference1,
reference2 = reference2,
destination = destination,
)
}
}
}

output.add(instruction)

if (destination != FusedDestination.ValueStack) {
nextIndex++
}

nextIndex
}
is ReferenceInstruction.RefIsNull -> {
var nextIndex = index

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package io.github.charlietap.chasm.predecoder.instruction.referencefused
import com.github.michaelbull.result.Result
import com.github.michaelbull.result.binding
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.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.value.ReferenceValue
Expand All @@ -25,6 +27,7 @@ internal fun FusedReferenceInstructionPredecoder(
instruction = instruction,
loadFactory = ::LoadFactory,
storeFactory = ::StoreFactory,
refEqDispatcher = ::RefEqDispatcher,
refIsNullDispatcher = ::RefIsNullDispatcher,
refNullDispatcher = ::RefNullDispatcher,
)
Expand All @@ -34,10 +37,25 @@ internal inline fun FusedReferenceInstructionPredecoder(
instruction: FusedReferenceInstruction,
crossinline loadFactory: LoadFactory,
crossinline storeFactory: StoreFactory,
crossinline refEqDispatcher: Dispatcher<RefEq>,
crossinline refIsNullDispatcher: Dispatcher<RefIsNull>,
crossinline refNullDispatcher: Dispatcher<RefNull>,
): Result<DispatchableInstruction, ModuleTrapError> = binding {
when (instruction) {
is FusedReferenceInstruction.RefEq -> {

val reference1 = loadFactory(context, instruction.reference1)
val reference2 = loadFactory(context, instruction.reference2)
val destination = storeFactory(context, instruction.destination)

refEqDispatcher(
RefEq(
reference1 = reference1,
reference2 = reference2,
destination = destination,
),
)
}
is FusedReferenceInstruction.RefIsNull -> {
val value = loadFactory(context, instruction.value)
val destination = storeFactory(context, instruction.destination)
Expand Down

0 comments on commit c52b1fe

Please sign in to comment.