Skip to content

Commit fc186b4

Browse files
committed
Add basic jsr / ret implementation
1 parent 2e70559 commit fc186b4

File tree

1 file changed

+88
-4
lines changed

1 file changed

+88
-4
lines changed

src/java_bytecode/java_bytecode_convert_method.cpp

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)