@@ -4,7 +4,7 @@ use crate::control_flow_graph::append_block_params;
44use crate :: instruction:: TRAP_INTERNAL_ERROR ;
55use crate :: local_variables:: LocalVariables ;
66use crate :: operand_stack:: OperandStack ;
7- use cranelift:: frontend:: FunctionBuilder ;
7+ use cranelift:: frontend:: { FunctionBuilder , Switch } ;
88use cranelift:: prelude:: { Block , InstBuilder , IntCC , TrapCode , Value , types} ;
99use ristretto_classfile:: attributes:: { LookupSwitch , TableSwitch } ;
1010use std:: collections:: HashMap ;
@@ -622,43 +622,29 @@ pub(crate) fn lookupswitch(
622622 program_counter : usize ,
623623 lookup_switch : & LookupSwitch ,
624624) -> Result < ( ) > {
625- // TODO: evaluate if the lookup switch can be optimized to a jump table.
626625 let index = stack. pop ( ) ?;
627- let block_arguments = stack. as_block_arguments ( ) ;
628- let stack_types = stack. to_type_vec ( function_builder) ;
629-
630- for ( & index_value, & offset) in & lookup_switch. pairs {
631- let else_block = function_builder. create_block ( ) ;
632- append_block_params ( function_builder, else_block, & stack_types) ;
633-
634- // PC = start of tableswitch + offset (signed arithmetic)
635- let target_address = usize:: try_from ( i32:: try_from ( program_counter) ?. wrapping_add ( offset) ) ?;
636- let block = * blocks
626+ // Create a Switch for efficient jump table generation; Cranelift will optimize it to use
627+ // branches, jump tables, or a combination of both
628+ let mut switch = Switch :: new ( ) ;
629+
630+ for ( case_value, offset) in & lookup_switch. pairs {
631+ let target_address =
632+ usize:: try_from ( i32:: try_from ( program_counter) ?. saturating_add ( * offset) ) ?;
633+ let target_block = * blocks
637634 . get ( & target_address)
638635 . ok_or_else ( || InvalidBlockAddress ( target_address) ) ?;
639- let index_value = i64:: from ( index_value) ;
640- let block_address = function_builder. ins ( ) . iconst ( types:: I32 , index_value) ;
641- let condition_value = function_builder
642- . ins ( )
643- . icmp ( IntCC :: Equal , index, block_address) ;
644- function_builder. ins ( ) . brif (
645- condition_value,
646- block,
647- & block_arguments,
648- else_block,
649- & block_arguments,
650- ) ;
651- function_builder. switch_to_block ( else_block) ;
636+
637+ let case_value = u128:: try_from ( * case_value) ?;
638+ switch. set_entry ( case_value, target_block) ;
652639 }
653640
654- // PC = start of tableswitch + default (signed arithmetic)
655641 let default_address =
656- usize:: try_from ( i32:: try_from ( program_counter) ?. wrapping_add ( lookup_switch. default ) ) ?;
657- let block = blocks
642+ usize:: try_from ( i32:: try_from ( program_counter) ?. saturating_add ( lookup_switch. default ) ) ?;
643+ let default_block = * blocks
658644 . get ( & default_address)
659645 . ok_or_else ( || InvalidBlockAddress ( default_address) ) ?;
660- let block_arguments = stack . as_block_arguments ( ) ;
661- function_builder . ins ( ) . jump ( * block , & block_arguments ) ;
646+
647+ switch . emit ( function_builder , index , default_block ) ;
662648 stack. reset ( function_builder) ?;
663649 Ok ( ( ) )
664650}
0 commit comments