Skip to content

Commit

Permalink
refisnull bytecode fusion
Browse files Browse the repository at this point in the history
  • Loading branch information
CharlieTap committed Feb 27, 2025
1 parent 60119b9 commit f5ec519
Show file tree
Hide file tree
Showing 6 changed files with 102 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.RefIsNullExecutor
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 RefIsNullDispatcher(
instruction: FusedReferenceInstruction.RefIsNull,
) = RefIsNullDispatcher(
instruction = instruction,
executor = ::RefIsNullExecutor,
)

internal inline fun RefIsNullDispatcher(
instruction: FusedReferenceInstruction.RefIsNull,
crossinline executor: Executor<FusedReferenceInstruction.RefIsNull>,
): DispatchableInstruction = { context ->
executor(context, instruction)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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 RefIsNullExecutor(
context: ExecutionContext,
instruction: FusedReferenceInstruction.RefIsNull,
) {
val stack = context.vstack
val value = instruction.value(stack)

if (value.isNullableReference()) {
instruction.destination(1L, stack)
} else {
instruction.destination(0L, stack)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ package io.github.charlietap.chasm.executor.runtime.instruction

sealed interface FusedReferenceInstruction : LinkedInstruction {

data class RefIsNull(
val value: LoadOp,
val destination: StoreOp,
) : FusedReferenceInstruction

data class RefNull(
val destination: StoreOp,
val reference: Long,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import io.github.charlietap.chasm.type.HeapType

sealed interface FusedReferenceInstruction : Instruction {

data class RefIsNull(
val value: FusedOperand,
val destination: FusedDestination,
) : FusedReferenceInstruction

data class RefNull(
val destination: FusedDestination,
val type: HeapType,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.charlietap.chasm.optimiser.passes.fusion

import io.github.charlietap.chasm.ir.instruction.FusedDestination
import io.github.charlietap.chasm.ir.instruction.FusedOperand
import io.github.charlietap.chasm.ir.instruction.FusedReferenceInstruction
import io.github.charlietap.chasm.ir.instruction.Instruction
import io.github.charlietap.chasm.ir.instruction.ReferenceInstruction
Expand All @@ -19,6 +20,7 @@ internal fun ReferenceInstructionFuser(
instruction = instruction,
input = input,
output = output,
operandFactory = ::FusedOperandFactory,
destinationFactory = ::FusedDestinationFactory,
)

Expand All @@ -28,8 +30,41 @@ internal inline fun ReferenceInstructionFuser(
instruction: ReferenceInstruction,
input: List<Instruction>,
output: MutableList<Instruction>,
operandFactory: FusedOperandFactory,
destinationFactory: FusedDestinationFactory,
): Int = when (instruction) {
is ReferenceInstruction.RefIsNull -> {
var nextIndex = index

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

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

output.add(instruction)

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ 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.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.RefIsNull
import io.github.charlietap.chasm.executor.runtime.instruction.FusedReferenceInstruction.RefNull
import io.github.charlietap.chasm.executor.runtime.value.ReferenceValue
import io.github.charlietap.chasm.ir.instruction.FusedReferenceInstruction
import io.github.charlietap.chasm.predecoder.LoadFactory
import io.github.charlietap.chasm.predecoder.PredecodingContext
import io.github.charlietap.chasm.predecoder.StoreFactory

Expand All @@ -20,17 +23,32 @@ internal fun FusedReferenceInstructionPredecoder(
FusedReferenceInstructionPredecoder(
context = context,
instruction = instruction,
loadFactory = ::LoadFactory,
storeFactory = ::StoreFactory,
refIsNullDispatcher = ::RefIsNullDispatcher,
refNullDispatcher = ::RefNullDispatcher,
)

internal inline fun FusedReferenceInstructionPredecoder(
context: PredecodingContext,
instruction: FusedReferenceInstruction,
crossinline loadFactory: LoadFactory,
crossinline storeFactory: StoreFactory,
crossinline refIsNullDispatcher: Dispatcher<RefIsNull>,
crossinline refNullDispatcher: Dispatcher<RefNull>,
): Result<DispatchableInstruction, ModuleTrapError> = binding {
when (instruction) {
is FusedReferenceInstruction.RefIsNull -> {
val value = loadFactory(context, instruction.value)
val destination = storeFactory(context, instruction.destination)

refIsNullDispatcher(
RefIsNull(
value = value,
destination = destination,
),
)
}
is FusedReferenceInstruction.RefNull -> {
val destination = storeFactory(context, instruction.destination)
val reference = ReferenceValue.Null(instruction.type).toLong()
Expand Down

0 comments on commit f5ec519

Please sign in to comment.