@@ -544,6 +544,9 @@ codet java_bytecode_convert_methodt::convert_instructions(
544
544
address_mapt address_map;
545
545
std::set<unsigned > targets;
546
546
547
+ std::vector<unsigned > jsr_ret_targets;
548
+ std::vector<instructionst::const_iterator> ret_instructions;
549
+
547
550
for (instructionst::const_iterator
548
551
i_it=instructions.begin ();
549
552
i_it!=instructions.end ();
@@ -586,6 +589,15 @@ codet java_bytecode_convert_methodt::convert_instructions(
586
589
targets.insert (target);
587
590
588
591
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
+ }
589
601
}
590
602
else if (i_it->statement ==" tableswitch" ||
591
603
i_it->statement ==" lookupswitch" )
@@ -603,6 +615,23 @@ codet java_bytecode_convert_methodt::convert_instructions(
603
615
is_label=!is_label;
604
616
}
605
617
}
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 ());
606
635
}
607
636
608
637
for (const auto &address : address_map)
@@ -921,6 +950,48 @@ codet java_bytecode_convert_methodt::convert_instructions(
921
950
code_gotot code_goto (label (number));
922
951
c=code_goto;
923
952
}
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
+ }
924
995
else if (statement==" iconst_m1" )
925
996
{
926
997
assert (results.size ()==1 );
@@ -1521,8 +1592,19 @@ codet java_bytecode_convert_methodt::convert_instructions(
1521
1592
else
1522
1593
{
1523
1594
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);
1526
1608
}
1527
1609
}
1528
1610
0 commit comments