@@ -544,6 +544,9 @@ codet java_bytecode_convert_methodt::convert_instructions(
544544 address_mapt address_map;
545545 std::set<unsigned > targets;
546546
547+ std::vector<unsigned > jsr_ret_targets;
548+ std::vector<instructionst::const_iterator> ret_instructions;
549+
547550 for (instructionst::const_iterator
548551 i_it=instructions.begin ();
549552 i_it!=instructions.end ();
@@ -586,6 +589,15 @@ codet java_bytecode_convert_methodt::convert_instructions(
586589 targets.insert (target);
587590
588591 a_entry.first ->second .successors .push_back (target);
592+
593+ if (i_it->statement ==" jsr" ||
594+ i_it->statement ==" jsr_w" )
595+ {
596+ instructionst::const_iterator next=i_it;
597+ assert (++next!=instructions.end () && " jsr without valid return address?" );
598+ targets.insert (next->address );
599+ jsr_ret_targets.push_back (next->address );
600+ }
589601 }
590602 else if (i_it->statement ==" tableswitch" ||
591603 i_it->statement ==" lookupswitch" )
@@ -603,6 +615,23 @@ codet java_bytecode_convert_methodt::convert_instructions(
603615 is_label=!is_label;
604616 }
605617 }
618+ else if (i_it->statement ==" ret" )
619+ {
620+ // Finish these later, once we've seen all jsr instructions.
621+ ret_instructions.push_back (i_it);
622+ }
623+ }
624+
625+ // Draw edges from every `ret` to every `jsr` successor.
626+ // Could do better with flow analysis to distinguish multiple subroutines within
627+ // the same function.
628+ for (const auto retinst : ret_instructions)
629+ {
630+ auto & a_entry=address_map.at (retinst->address );
631+ a_entry.successors .insert (
632+ a_entry.successors .end (),
633+ jsr_ret_targets.begin (),
634+ jsr_ret_targets.end ());
606635 }
607636
608637 for (const auto &address : address_map)
@@ -921,6 +950,48 @@ codet java_bytecode_convert_methodt::convert_instructions(
921950 code_gotot code_goto (label (number));
922951 c=code_goto;
923952 }
953+ else if (statement==" jsr" || statement==" jsr_w" )
954+ {
955+ // As 'goto', except we must also push the subroutine return address:
956+ assert (op.empty () && results.size ()==1 );
957+ irep_idt number=to_constant_expr (arg0).get_value ();
958+ code_gotot code_goto (label (number));
959+ c=code_goto;
960+ results[0 ]=as_number (
961+ std::next (i_it)->address ,
962+ pointer_typet (void_typet (), 64 ));
963+ }
964+ else if (statement==" ret" )
965+ {
966+ // Since we have a bounded target set, make life easier on our analyses
967+ // and write something like:
968+ // if(retaddr==5) goto 5; else if(retaddr==10) goto 10; ...
969+ assert (op.empty () && results.empty ());
970+ code_blockt branches;
971+ auto retvar=variable (arg0, ' a' , i_it->address , INST_INDEX, NO_CAST);
972+ assert (!jsr_ret_targets.empty ());
973+ for (size_t idx=0 , idxlim=jsr_ret_targets.size (); idx!=idxlim; ++idx)
974+ {
975+ irep_idt number=std::to_string (jsr_ret_targets[idx]);
976+ code_gotot g (label (number));
977+ g.add_source_location ()=i_it->source_location ;
978+ if (idx==idxlim-1 )
979+ branches.move_to_operands (g);
980+ else
981+ {
982+ code_ifthenelset branch;
983+ auto address_ptr=as_number (
984+ jsr_ret_targets[idx],
985+ pointer_typet (void_typet (), 64 ));
986+ branch.cond ()=equal_exprt (retvar, address_ptr);
987+ branch.cond ().add_source_location ()=i_it->source_location ;
988+ branch.then_case ()=g;
989+ branch.add_source_location ()=i_it->source_location ;
990+ branches.move_to_operands (branch);
991+ }
992+ }
993+ c=std::move (branches);
994+ }
924995 else if (statement==" iconst_m1" )
925996 {
926997 assert (results.size ()==1 );
@@ -1521,8 +1592,19 @@ codet java_bytecode_convert_methodt::convert_instructions(
15211592 else
15221593 {
15231594 c.make_block ();
1524- forall_operands (o_it, more_code)
1525- c.copy_to_operands (*o_it);
1595+ auto & last_statement=to_code_block (c).find_last_statement ();
1596+ if (last_statement.get_statement ()==ID_goto)
1597+ {
1598+ // Insert stack twiddling before branch:
1599+ last_statement.make_block ();
1600+ last_statement.operands ().insert (
1601+ last_statement.operands ().begin (),
1602+ more_code.operands ().begin (),
1603+ more_code.operands ().end ());
1604+ }
1605+ else
1606+ forall_operands (o_it, more_code)
1607+ c.copy_to_operands (*o_it);
15261608 }
15271609 }
15281610
0 commit comments