@@ -676,6 +676,9 @@ codet java_bytecode_convert_methodt::convert_instructions(
676676 address_mapt address_map;
677677 std::set<unsigned > targets;
678678
679+ std::vector<unsigned > jsr_ret_targets;
680+ std::vector<instructionst::const_iterator> ret_instructions;
681+
679682 for (instructionst::const_iterator
680683 i_it=instructions.begin ();
681684 i_it!=instructions.end ();
@@ -693,7 +696,10 @@ codet java_bytecode_convert_methodt::convert_instructions(
693696 if (i_it->statement !=" goto" &&
694697 i_it->statement !=" return" &&
695698 !(i_it->statement ==patternt (" ?return" )) &&
696- i_it->statement !=" athrow" )
699+ i_it->statement !=" athrow" &&
700+ i_it->statement !=" jsr" &&
701+ i_it->statement !=" jsr_w" &&
702+ i_it->statement !=" ret" )
697703 {
698704 instructionst::const_iterator next=i_it;
699705 if (++next!=instructions.end ())
@@ -704,7 +710,9 @@ codet java_bytecode_convert_methodt::convert_instructions(
704710 i_it->statement ==patternt (" if_?cmp??" ) ||
705711 i_it->statement ==patternt (" if??" ) ||
706712 i_it->statement ==" ifnonnull" ||
707- i_it->statement ==" ifnull" )
713+ i_it->statement ==" ifnull" ||
714+ i_it->statement ==" jsr" ||
715+ i_it->statement ==" jsr_w" )
708716 {
709717 assert (!i_it->args .empty ());
710718
@@ -713,6 +721,14 @@ codet java_bytecode_convert_methodt::convert_instructions(
713721 targets.insert (target);
714722
715723 a_entry.first ->second .successors .push_back (target);
724+
725+ if (i_it->statement ==" jsr" ||
726+ i_it->statement ==" jsr_w" )
727+ {
728+ instructionst::const_iterator next=i_it;
729+ assert (++next!=instructions.end () && " jsr without valid return address?" );
730+ jsr_ret_targets.push_back (next->address );
731+ }
716732 }
717733 else if (i_it->statement ==" tableswitch" ||
718734 i_it->statement ==" lookupswitch" )
@@ -732,6 +748,22 @@ codet java_bytecode_convert_methodt::convert_instructions(
732748 }
733749 }
734750 }
751+ else if (i_it->statement ==" ret" )
752+ {
753+ // Finish these later, once we've seen all jsr instructions.
754+ ret_instructions.push_back (i_it);
755+ }
756+ }
757+
758+ // Draw edges from every `ret` to every `jsr` successor.
759+ // Could do better with flow analysis to distinguish multiple subroutines within
760+ // the same function.
761+ for (const auto retinst : ret_instructions)
762+ {
763+ auto & a_entry=address_map.at (retinst->address );
764+ a_entry.successors .insert (a_entry.successors .end (),
765+ jsr_ret_targets.begin (),
766+ jsr_ret_targets.end ());
735767 }
736768
737769 for (address_mapt::iterator
@@ -1114,6 +1146,46 @@ codet java_bytecode_convert_methodt::convert_instructions(
11141146 code_gotot code_goto (label (number));
11151147 c=code_goto;
11161148 }
1149+ else if (statement==" jsr" || statement==" jsr_w" )
1150+ {
1151+ // As 'goto', except we must also push the subroutine return address:
1152+ assert (op.empty () && results.size ()==1 );
1153+ irep_idt number=to_constant_expr (arg0).get_value ();
1154+ code_gotot code_goto (label (number));
1155+ c=code_goto;
1156+ results[0 ]=as_number (std::next (i_it)->address ,pointer_typet (void_typet (),64 ));
1157+ }
1158+ else if (statement==" ret" )
1159+ {
1160+ // Since we have a bounded target set, make life easier on our analyses
1161+ // and write something like if(retaddr==5) goto 5; else if(retaddr==10) goto 10; ...
1162+ assert (op.empty () && results.empty ());
1163+ code_blockt branches;
1164+ auto retvar=variable (arg0, ' a' , i_it->address );
1165+ assert (!jsr_ret_targets.empty ());
1166+ for (size_t idx=0 , idxlim=jsr_ret_targets.size (); idx!=idxlim; ++idx)
1167+ {
1168+ irep_idt number=i2string (jsr_ret_targets[idx]);
1169+ code_gotot g (label (number));
1170+ g.add_source_location ()=i_it->source_location ;
1171+ g.add_source_location ().set_function (method_id);
1172+ if (idx==idxlim-1 )
1173+ branches.move_to_operands (g);
1174+ else
1175+ {
1176+ code_ifthenelset branch;
1177+ auto address_ptr=as_number (jsr_ret_targets[idx],pointer_typet (void_typet (),64 ));
1178+ branch.cond ()=equal_exprt (retvar,address_ptr);
1179+ branch.cond ().add_source_location ()=i_it->source_location ;
1180+ branch.cond ().add_source_location ().set_function (method_id);
1181+ branch.then_case ()=g;
1182+ branch.add_source_location ()=i_it->source_location ;
1183+ branch.add_source_location ().set_function (method_id);
1184+ branches.move_to_operands (branch);
1185+ }
1186+ }
1187+ c=std::move (branches);
1188+ }
11171189 else if (statement==" iconst_m1" )
11181190 {
11191191 assert (results.size ()==1 );
@@ -1747,8 +1819,18 @@ codet java_bytecode_convert_methodt::convert_instructions(
17471819 else
17481820 {
17491821 c.make_block ();
1750- forall_operands (o_it, more_code)
1751- c.copy_to_operands (*o_it);
1822+ auto & last_statement=to_code_block (c).find_last_statement ();
1823+ if (last_statement.get_statement ()==ID_goto)
1824+ {
1825+ // Insert stack twiddling before branch:
1826+ last_statement.make_block ();
1827+ last_statement.operands ().insert (last_statement.operands ().begin (),
1828+ more_code.operands ().begin (),
1829+ more_code.operands ().end ());
1830+ }
1831+ else
1832+ forall_operands (o_it, more_code)
1833+ c.copy_to_operands (*o_it);
17521834 }
17531835 }
17541836
@@ -1807,6 +1889,8 @@ codet java_bytecode_convert_methodt::convert_instructions(
18071889 start_new_block=targets.find (address)!=targets.end ();
18081890 if (!start_new_block)
18091891 start_new_block=it.second .predecessors .size ()>1 ;
1892+ if ((!start_new_block) && it.second .predecessors .size ()==1 )
1893+ start_new_block=*(it.second .predecessors .begin ())!=std::prev (ait)->first ;
18101894
18111895 if (start_new_block)
18121896 {
0 commit comments