32 cfg_base_nodet<T, java_bytecode_convert_methodt::method_offsett>>
49 const auto &method=args.first;
50 const auto &amap=args.second;
51 for(
const auto &inst : amap)
56 (*this)[entry_map[inst.first]].PC=inst.first;
59 for(
const auto &inst : amap)
61 for(
auto succ : inst.second.successors)
66 for(
const auto &table_entry : method.exception_table)
68 auto findit=amap.find(table_entry.start_pc);
71 "Exception table entry doesn't point to an instruction?");
72 for(; findit->first<table_entry.end_pc; ++findit)
78 if(succit==amap.end())
80 const auto &thisinst=findit->second;
81 if(thisinst.successors.size()==1 &&
82 thisinst.successors.back()==succit->first)
85 entry_map.at(findit->first),
112 return args.second.begin()->first;
118 return (--args.second.end())->first;
123 return args.second.empty();
158 std::set<local_variable_with_holest *> >
171 auto findit=
order.find(a);
172 if(findit==
order.end())
174 return findit->second.count(b)>0;
188 std::set<local_variable_with_holest*> &result)
190 if(!result.insert(start).second)
192 auto findit=predecessor_map.find(start);
193 if(findit==predecessor_map.end())
195 for(
const auto pred : findit->second)
210 if(!(prevstatement.size()>=1 && prevstatement.substr(1, 5)==
"store"))
213 unsigned storeslotidx;
214 if(inst.
args.size()==1)
217 const auto &arg=inst.
args[0];
224 prevstatement[6]==
'_' && prevstatement.size()==8,
225 "expected store instruction looks like store_0, store_1...");
226 std::string storeslot(1, prevstatement[7]);
228 isdigit(storeslot[0]),
229 "store_? instructions should end in a digit");
232 return storeslotidx==slotidx;
259 local_variable_table_with_holest::iterator firstvar,
260 local_variable_table_with_holest::iterator varlimit,
261 std::vector<local_variable_with_holest *> &live_variable_at_address)
263 for(
auto it=firstvar, itend=varlimit; it!=itend; ++it)
265 if(it->var.start_pc+it->var.length>live_variable_at_address.size())
266 live_variable_at_address.resize(it->var.start_pc+it->var.length);
268 for(
auto idx = it->var.start_pc, idxlim = it->var.start_pc + it->var.length;
272 INVARIANT(!live_variable_at_address[idx],
"Local variable table clash?");
273 live_variable_at_address[idx]=&*it;
304 local_variable_table_with_holest::iterator firstvar,
305 local_variable_table_with_holest::iterator varlimit,
306 const std::vector<local_variable_with_holest *> &live_variable_at_address,
312 for(
auto it=firstvar, itend=varlimit; it!=itend; ++it)
318 it->var.index==firstvar->var.index,
319 "all entries are for the same local variable slot");
328 msg.
debug() <<
"jcm: ppm: processing var idx " << it->var.index
329 <<
" name '" << it->var.name <<
"' start-pc "
330 << it->var.start_pc <<
" len " << it->var.length
335 const auto end_pc = it->var.start_pc + it->var.length;
336 auto amapit=amap.find(end_pc);
338 amapit!=amap.begin(),
339 "current bytecode shall not be the first");
340 auto old_amapit=amapit;
342 if(old_amapit==amap.end())
345 end_pc>amapit->first,
346 "Instruction live range doesn't align to instruction boundary?");
354 auto new_start_pc = it->var.start_pc;
355 for(; amapit->first>=it->var.start_pc; --amapit)
357 for(
auto pred : amapit->second.predecessors)
365 (pred<live_variable_at_address.size() ?
366 live_variable_at_address[pred] :
382 auto inst_before_this=amapit;
384 inst_before_this!=amap.begin(),
385 "we shall not be on the first bytecode of the method");
387 if(amapit->first!=it->var.start_pc || inst_before_this->first!=pred)
392 msg.
warning() <<
"Local variable table: ignoring flow from "
393 <<
"out of range for " << it->var.name <<
' '
394 << pred <<
" -> " << amapit->first
399 *(inst_before_this->second.source),
402 msg.
warning() <<
"Local variable table: didn't find initializing "
403 <<
"store for predecessor of bytecode at address "
404 << amapit->first <<
" ("
405 << amapit->second.predecessors.size()
406 <<
" predecessors)" << msg.
eom;
407 throw "local variable table: unexpected live ranges";
415 if(pred_var->var.name!=it->var.name ||
416 pred_var->var.descriptor!=it->var.descriptor)
421 msg.
warning() <<
"Local variable table: ignoring flow from "
422 <<
"clashing variable for "
423 << it->var.name <<
' ' << pred <<
" -> "
429 predecessor_map[&*it].insert(pred_var);
436 it->var.length+=(it->var.start_pc-new_start_pc);
437 it->var.start_pc=new_start_pc;
449 const std::set<local_variable_with_holest *> &merge_vars,
455 std::numeric_limits<java_bytecode_convert_methodt::method_offsett>::max();
456 for(
auto v : merge_vars)
458 if(v->var.start_pc<first_pc)
459 first_pc=v->var.start_pc;
462 std::vector<java_bytecode_convert_methodt::method_offsett>
463 candidate_dominators;
464 for(
auto v : merge_vars)
466 const auto &dominator_nodeidx=
468 const auto &this_var_doms=
469 dominator_analysis.
cfg[dominator_nodeidx].dominators;
470 for(
const auto this_var_dom : this_var_doms)
471 if(this_var_dom<=first_pc)
472 candidate_dominators.push_back(this_var_dom);
474 std::sort(candidate_dominators.begin(), candidate_dominators.end());
479 for(
auto domit=candidate_dominators.rbegin(),
480 domitend=candidate_dominators.rend();
484 std::size_t repeats = 0;
486 while(domit!=domitend && *domit==dom)
491 assert(repeats<=merge_vars.size());
492 if(repeats==merge_vars.size())
496 throw "variable live ranges with no common dominator?";
509 const std::set<local_variable_with_holest *> &merge_vars,
512 std::vector<local_variable_with_holest *> sorted_by_startpc(
513 merge_vars.begin(), merge_vars.end());
514 std::sort(sorted_by_startpc.begin(), sorted_by_startpc.end(),
lt_startpc);
519 expanded_live_range_start,
520 sorted_by_startpc[0]->var.start_pc);
521 for(
auto it = std::next(sorted_by_startpc.begin());
522 it != sorted_by_startpc.end();
525 auto &local_var = (*std::prev(it))->var;
527 merge_into, local_var.start_pc + local_var.length, (*it)->
var.
start_pc);
541 const std::set<local_variable_with_holest *> &merge_vars,
543 std::ostream &debug_out)
549 const auto found_dominator =
559 for(
auto v : merge_vars)
561 if(v->var.start_pc+v->var.length>last_pc)
562 last_pc=v->var.start_pc+v->var.length;
567 merge_into.
var.
length=last_pc-found_dominator;
570 debug_out <<
"Merged " << merge_vars.size() <<
" variables named "
571 << merge_into.
var.
name <<
"; new live range "
579 for(
auto &v : merge_vars)
598 local_variable_table_with_holest::iterator firstvar,
599 local_variable_table_with_holest::iterator varlimit,
606 std::vector<local_variable_with_holest *> live_variable_at_address;
616 live_variable_at_address,
625 for(
auto &kv : predecessor_map)
627 std::set<local_variable_with_holest *> closed_preds;
629 kv.second=std::move(closed_preds);
634 std::vector<local_variable_with_holest *> topsorted_vars;
635 for(
auto it=firstvar, itend=varlimit; it!=itend; ++it)
636 topsorted_vars.push_back(&*it);
638 std::sort(topsorted_vars.begin(), topsorted_vars.end(), comp);
641 for(
auto merge_into : topsorted_vars)
644 if(merge_into->var.length==0)
647 auto findit=predecessor_map.find(merge_into);
649 if(findit==predecessor_map.end())
652 const auto &merge_vars=findit->second;
653 INVARIANT(merge_vars.size()>=2,
"merging requires at least 2 variables");
656 *merge_into, merge_vars, dominator_analysis,
log.
status());
668 local_variable_table_with_holest::iterator &it1,
669 local_variable_table_with_holest::iterator &it2,
670 local_variable_table_with_holest::iterator itend)
679 auto index=it2->var.index;
680 while(it2!=itend && it2->var.index==index)
697 std::sort(vars.begin(), vars.end(),
lt_index);
701 auto it1=vars.begin();
703 auto itend=vars.end();
713 std::vector<local_variable_with_holest> &vars_with_holes)
716 for(
size_t i=0; i<(vars_with_holes.size()-toremove); ++i)
718 auto &v=vars_with_holes[i];
723 if(i!=vars_with_holes.size()-toremove)
724 std::swap(v, vars_with_holes[vars_with_holes.size()-toremove]);
731 vars_with_holes.resize(vars_with_holes.size()-toremove);
747 dominator_analysis(dominator_args);
754 log.
debug() <<
"jcm: setup-local-vars: lvt size "
761 std::vector<local_variable_with_holest> vars_with_holes;
776 catch(
const char *message)
778 log.
warning() <<
"Bytecode -> codet translation error: " << message
780 <<
"This is probably due to an unexpected LVT, "
781 <<
"falling back to translation without LVT" <<
messaget::eom;
796 for(
auto &v : vars_with_holes)
802 log.
debug() <<
"jcm: setup-local-vars: merged variable: idx " << v.var.index
803 <<
" name " << v.var.name <<
" v.var.descriptor '"
804 << v.var.descriptor <<
"' holes " << v.holes.size()
809 const size_t method_name_end = method_name.rfind(
":(");
810 const size_t class_name_end = method_name.rfind(
'.', method_name_end);
812 method_name_end != std::string::npos &&
813 class_name_end != std::string::npos,
814 "A method name has the format class `.` method `:(`signature`)`.");
815 const std::string class_name = method_name.substr(0, class_name_end);
817 const typet t = v.var.signature.has_value()
819 v.var.descriptor, v.var.signature, class_name)
822 std::ostringstream id_oss;
823 id_oss <<
method_id <<
"::" << v.var.start_pc <<
"::" << v.var.name;
826 result.
set(ID_C_base_name, v.var.name);
832 result, v.var.start_pc, v.var.length,
false, std::move(v.holes));
836 new_symbol.
name=identifier;
840 new_symbol.
mode=ID_java;
863 size_t length=var.length;
864 if(address>=start_pc && address<(start_pc+length))
866 bool found_hole=
false;
867 for(
auto &hole : var.holes)
868 if(address>=hole.start_pc && address<(hole.start_pc+hole.length))
882 var_list.emplace_back(
884 return var_list.back();