Skip to content

Commit 059ae08

Browse files
committed
refactor: optimize jit tableswitch instruction
1 parent 197acb8 commit 059ae08

File tree

1 file changed

+16
-29
lines changed

1 file changed

+16
-29
lines changed

ristretto_jit/src/instruction/branch.rs

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::control_flow_graph::append_block_params;
44
use crate::instruction::TRAP_INTERNAL_ERROR;
55
use crate::local_variables::LocalVariables;
66
use crate::operand_stack::OperandStack;
7-
use cranelift::frontend::FunctionBuilder;
7+
use cranelift::frontend::{FunctionBuilder, Switch};
88
use cranelift::prelude::{Block, InstBuilder, IntCC, TrapCode, Value, types};
99
use ristretto_classfile::attributes::{LookupSwitch, TableSwitch};
1010
use std::collections::HashMap;
@@ -573,43 +573,30 @@ pub(crate) fn tableswitch(
573573
program_counter: usize,
574574
table_switch: &TableSwitch,
575575
) -> Result<()> {
576-
// TODO: evaluate if the table switch can be optimized to a jump table.
577576
let index = stack.pop()?;
578-
let block_arguments = stack.as_block_arguments();
579-
let stack_types = stack.to_type_vec(function_builder);
577+
// Create a Switch for efficient jump table generation; Cranelift will optimize it to use
578+
// branches, jump tables, or a combination of both
579+
let mut switch = Switch::new();
580580

581581
for (offset_index, &offset) in table_switch.offsets.iter().enumerate() {
582-
let else_block = function_builder.create_block();
583-
append_block_params(function_builder, else_block, &stack_types);
584-
585-
// PC = start of tableswitch + offset (signed arithmetic)
586-
let target_address = usize::try_from(i32::try_from(program_counter)?.wrapping_add(offset))?;
587-
let block = *blocks
582+
let target_address =
583+
usize::try_from(i32::try_from(program_counter)?.saturating_add(offset))?;
584+
let target_block = *blocks
588585
.get(&target_address)
589586
.ok_or_else(|| InvalidBlockAddress(target_address))?;
590-
let offset_value = i64::from(table_switch.low).saturating_add(i64::try_from(offset_index)?);
591-
let block_address = function_builder.ins().iconst(types::I32, offset_value);
592-
let condition_value = function_builder
593-
.ins()
594-
.icmp(IntCC::Equal, index, block_address);
595-
function_builder.ins().brif(
596-
condition_value,
597-
block,
598-
&block_arguments,
599-
else_block,
600-
&block_arguments,
601-
);
602-
function_builder.switch_to_block(else_block);
587+
588+
let case_value = i64::from(table_switch.low).saturating_add(i64::try_from(offset_index)?);
589+
let case_value = u128::try_from(case_value)?;
590+
switch.set_entry(case_value, target_block);
603591
}
604592

605-
// PC = start of tableswitch + default (signed arithmetic)
606593
let default_address =
607-
usize::try_from(i32::try_from(program_counter)?.wrapping_add(table_switch.default))?;
608-
let block = blocks
594+
usize::try_from(i32::try_from(program_counter)?.saturating_add(table_switch.default))?;
595+
let default_block = *blocks
609596
.get(&default_address)
610597
.ok_or_else(|| InvalidBlockAddress(default_address))?;
611-
let block_arguments = stack.as_block_arguments();
612-
function_builder.ins().jump(*block, &block_arguments);
598+
599+
switch.emit(function_builder, index, default_block);
613600
stack.reset(function_builder)?;
614601
Ok(())
615602
}
@@ -653,7 +640,7 @@ pub(crate) fn lookupswitch(
653640

654641
// PC = start of tableswitch + default (signed arithmetic)
655642
let default_address =
656-
usize::try_from(i32::try_from(program_counter)?.wrapping_add(lookup_switch.default))?;
643+
usize::try_from(i32::try_from(program_counter)?.saturating_add(lookup_switch.default))?;
657644
let block = blocks
658645
.get(&default_address)
659646
.ok_or_else(|| InvalidBlockAddress(default_address))?;

0 commit comments

Comments
 (0)