cprover
java_local_variable_table.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Java local variable table processing
4 
5 Author: Chris Smowton, chris.smowton@diffblue.com
6 
7 \*******************************************************************/
8 
11 
13 
14 #include "java_types.h"
15 #include "java_utils.h"
16 
17 #include <util/arith_tools.h>
18 #include <util/invariant.h>
19 #include <util/string2int.h>
20 
21 #include <climits>
22 #include <iostream>
23 
24 // Specialise the CFG representation to work over Java instead of GOTO programs.
25 // This must be done at global scope due to template resolution rules.
26 
27 template<class T>
29  T,
31  unsigned> :
32  public grapht<cfg_base_nodet<T, unsigned> >
33 {
35  typedef std::map<unsigned, unsigned> entry_mapt;
37 
39 
40  void operator()(const method_with_amapt &args)
41  {
42  const auto &method=args.first;
43  const auto &amap=args.second;
44  for(const auto &inst : amap)
45  {
46  // Map instruction PCs onto node indices:
47  entry_map[inst.first]=this->add_node();
48  // Map back:
49  (*this)[entry_map[inst.first]].PC=inst.first;
50  }
51  // Add edges declared in the address map:
52  for(const auto &inst : amap)
53  {
54  for(auto succ : inst.second.successors)
55  this->add_edge(entry_map.at(inst.first), entry_map.at(succ));
56  }
57  // Next, add edges declared in the exception table, which
58  // don't figure in the address map successors/predecessors as yet:
59  for(const auto &table_entry : method.exception_table)
60  {
61  auto findit=amap.find(table_entry.start_pc);
62  INVARIANT(
63  findit!=amap.end(),
64  "Exception table entry doesn't point to an instruction?");
65  for(; findit->first<table_entry.end_pc; ++findit)
66  {
67  // For now just assume any non-branch
68  // instruction could potentially throw.
69  auto succit=findit;
70  ++succit;
71  if(succit==amap.end())
72  continue;
73  const auto &thisinst=findit->second;
74  if(thisinst.successors.size()==1 &&
75  thisinst.successors.back()==succit->first)
76  {
77  this->add_edge(
78  entry_map.at(findit->first),
79  entry_map.at(table_entry.handler_pc));
80  }
81  }
82  }
83  }
84 
85  unsigned get_first_node(const method_with_amapt &args) const
86  {
87  return args.second.begin()->first;
88  }
89 
90  unsigned get_last_node(const method_with_amapt &args) const
91  {
92  return (--args.second.end())->first;
93  }
94 
95  unsigned nodes_empty(const method_with_amapt &args) const
96  {
97  return args.second.empty();
98  }
99 };
100 
101 // Grab some class typedefs for brevity:
112 
113 // Comparators for local variables:
114 
115 static bool lt_index(
118 {
119  return a.var.index<b.var.index;
120 }
121 static bool lt_startpc(
124 {
125  return a->var.start_pc<b->var.start_pc;
126 }
127 
128 // The predecessor map, and a top-sorting comparator:
129 
130 typedef std::map<
132  std::set<local_variable_with_holest *> >
134 
136 {
138 
139  explicit is_predecessor_oft(const predecessor_mapt &_order) : order(_order) {}
140 
144  {
145  auto findit=order.find(a);
146  if(findit==order.end())
147  return false;
148  return findit->second.count(b)>0;
149  }
150 };
151 
152 // Helper routines for the find-initializers code below:
153 
161  const predecessor_mapt &predecessor_map,
162  std::set<local_variable_with_holest*> &result)
163 {
164  if(!result.insert(start).second)
165  return;
166  auto findit=predecessor_map.find(start);
167  if(findit==predecessor_map.end())
168  return;
169  for(const auto pred : findit->second)
170  gather_transitive_predecessors(pred, predecessor_map, result);
171 }
172 
178 static bool is_store_to_slot(
180  unsigned slotidx)
181 {
182  const std::string prevstatement=id2string(inst.statement);
183  if(!(prevstatement.size()>=1 && prevstatement.substr(1, 5)=="store"))
184  return false;
185 
186  unsigned storeslotidx;
187  if(inst.args.size()==1)
188  {
189  // Store with an argument:
190  const auto &arg=inst.args[0];
191  bool ret=to_unsigned_integer(to_constant_expr(arg), storeslotidx);
192  CHECK_RETURN(!ret);
193  }
194  else
195  {
196  // Store shorthands, like "store_0", "store_1"
197  INVARIANT(
198  prevstatement[6]=='_' && prevstatement.size()==8,
199  "expected store instruction looks like store_0, store_1...");
200  std::string storeslot(1, prevstatement[7]);
201  INVARIANT(
202  isdigit(storeslot[0]),
203  "store_? instructions should end in a digit");
204  storeslotidx=safe_string2unsigned(storeslot);
205  }
206  return storeslotidx==slotidx;
207 }
208 
213 static void maybe_add_hole(
215  unsigned from,
216  unsigned to)
217 {
218  PRECONDITION(to>=from);
219  if(to!=from)
220  var.holes.push_back({from, to-from});
221 }
222 
231  local_variable_table_with_holest::iterator firstvar,
232  local_variable_table_with_holest::iterator varlimit,
233  std::vector<local_variable_with_holest *> &live_variable_at_address)
234 {
235  for(auto it=firstvar, itend=varlimit; it!=itend; ++it)
236  {
237  if(it->var.start_pc+it->var.length>live_variable_at_address.size())
238  live_variable_at_address.resize(it->var.start_pc+it->var.length);
239 
240  for(unsigned idx=it->var.start_pc,
241  idxlim=it->var.start_pc+it->var.length;
242  idx!=idxlim;
243  ++idx)
244  {
245  INVARIANT(!live_variable_at_address[idx], "Local variable table clash?");
246  live_variable_at_address[idx]=&*it;
247  }
248  }
249 }
250 
268 // live at that address
275  local_variable_table_with_holest::iterator firstvar,
276  local_variable_table_with_holest::iterator varlimit,
277  const std::vector<local_variable_with_holest *> &live_variable_at_address,
278  const address_mapt &amap,
279  predecessor_mapt &predecessor_map,
280  message_handlert &msg_handler)
281 {
282  messaget msg(msg_handler);
283  for(auto it=firstvar, itend=varlimit; it!=itend; ++it)
284  {
285  // All entries of the "local_variable_table_with_holest" processed in this
286  // function concern the same Java Local Variable Table slot/register. This
287  // is because "find_initializers()" has already sorted them.
288  INVARIANT(
289  it->var.index==firstvar->var.index,
290  "all entries are for the same local variable slot");
291 
292  // Parameters are irrelevant to us and shouldn't be changed. This is because
293  // they cannot have live predecessor ranges: they are initialized by the JVM
294  // and no other live variable range can flow into them.
295  if(it->is_parameter)
296  continue;
297 
298 #ifdef DEBUG
299  msg.debug() << "jcm: ppm: processing var idx " << it->var.index
300  << " name '" << it->var.name << "' start-pc "
301  << it->var.start_pc << " len " << it->var.length
302  << "; holes " << it->holes.size() << messaget::eom;
303 #endif
304 
305  // Find the last instruction within the live range:
306  unsigned end_pc=it->var.start_pc+it->var.length;
307  auto amapit=amap.find(end_pc);
308  INVARIANT(
309  amapit!=amap.begin(),
310  "current bytecode shall not be the first");
311  auto old_amapit=amapit;
312  --amapit;
313  if(old_amapit==amap.end())
314  {
315  INVARIANT(
316  end_pc>amapit->first,
317  "Instruction live range doesn't align to instruction boundary?");
318  }
319 
320  // Find vartable entries that flow into this one. For unknown reasons this
321  // loop iterates backwards, walking back from the last bytecode in the live
322  // range of variable it to the first one. For each value of the iterator
323  // "amapit" we search for instructions that jump into amapit's address
324  // (predecessors)
325  unsigned new_start_pc=it->var.start_pc;
326  for(; amapit->first>=it->var.start_pc; --amapit)
327  {
328  for(auto pred : amapit->second.predecessors)
329  {
330  // pred is the address (byecode offset) of a instruction that jumps into
331  // amapit. Compute now a pointer to the variable-with-holes whose index
332  // equals that of amapit and which was alive on instruction pred, or a
333  // null pointer if no such variable exists (e.g., because no live range
334  // covers that instruction)
335  auto pred_var=
336  (pred<live_variable_at_address.size() ?
337  live_variable_at_address[pred] :
338  nullptr);
339 
340  // Three cases are now possible:
341  // 1. The predecessor instruction is in the same live range: nothing to
342  // do.
343  if(pred_var==&*it)
344  {
345  continue;
346  }
347  // 2. The predecessor instruction is in no live range among those for
348  // variable slot it->var.index
349  else if(!pred_var)
350  {
351  // Check if this is an initializer, and if so expand the live range
352  // to include it, but don't check its predecessors:
353  auto inst_before_this=amapit;
354  INVARIANT(
355  inst_before_this!=amap.begin(),
356  "we shall not be on the first bytecode of the method");
357  --inst_before_this;
358  if(amapit->first!=it->var.start_pc || inst_before_this->first!=pred)
359  {
360  // These sorts of infeasible edges can occur because jsr
361  // handling is presently vague (any subroutine is assumed to
362  // be able to return to any callsite)
363  msg.warning() << "Local variable table: ignoring flow from "
364  << "out of range for " << it->var.name << ' '
365  << pred << " -> " << amapit->first
366  << messaget::eom;
367  continue;
368  }
369  if(!is_store_to_slot(
370  *(inst_before_this->second.source),
371  it->var.index))
372  {
373  msg.warning() << "Local variable table: didn't find initializing "
374  << "store for predecessor of bytecode at address "
375  << amapit->first << " ("
376  << amapit->second.predecessors.size()
377  << " predecessors)" << msg.eom;
378  throw "local variable table: unexpected live ranges";
379  }
380  new_start_pc=pred;
381  }
382  // 3. Predecessor instruction is a different range associated to the
383  // same variable slot
384  else
385  {
386  if(pred_var->var.name!=it->var.name ||
387  pred_var->var.descriptor!=it->var.descriptor)
388  {
389  // These sorts of infeasible edges can occur because
390  // jsr handling is presently vague (any subroutine is
391  // assumed to be able to return to any callsite)
392  msg.warning() << "Local variable table: ignoring flow from "
393  << "clashing variable for "
394  << it->var.name << ' ' << pred << " -> "
395  << amapit->first << messaget::eom;
396  continue;
397  }
398  // OK, this is a flow from a similar but
399  // distinct entry in the local var table.
400  predecessor_map[&*it].insert(pred_var);
401  }
402  }
403  }
404 
405  // If a simple pre-block initializer was found,
406  // add it to the live range now:
407  it->var.length+=(it->var.start_pc-new_start_pc);
408  it->var.start_pc=new_start_pc;
409  }
410 }
411 
420 static unsigned get_common_dominator(
421  const std::set<local_variable_with_holest*> &merge_vars,
422  const java_cfg_dominatorst &dominator_analysis)
423 {
424  PRECONDITION(!merge_vars.empty());
425 
426  unsigned first_pc=UINT_MAX;
427  for(auto v : merge_vars)
428  {
429  if(v->var.start_pc<first_pc)
430  first_pc=v->var.start_pc;
431  }
432 
433  std::vector<unsigned> candidate_dominators;
434  for(auto v : merge_vars)
435  {
436  const auto &dominator_nodeidx=
437  dominator_analysis.cfg.entry_map.at(v->var.start_pc);
438  const auto &this_var_doms=
439  dominator_analysis.cfg[dominator_nodeidx].dominators;
440  for(const auto this_var_dom : this_var_doms)
441  if(this_var_dom<=first_pc)
442  candidate_dominators.push_back(this_var_dom);
443  }
444  std::sort(candidate_dominators.begin(), candidate_dominators.end());
445 
446  // Working from the back, simply find the first PC
447  // that occurs merge_vars.size() times and therefore
448  // dominates all vars we seek to merge:
449  for(auto domit=candidate_dominators.rbegin(),
450  domitend=candidate_dominators.rend();
451  domit!=domitend;
452  /* Don't increment here */)
453  {
454  unsigned repeats=0;
455  auto dom=*domit;
456  while(domit!=domitend && *domit==dom)
457  {
458  ++domit;
459  ++repeats;
460  }
461  assert(repeats<=merge_vars.size());
462  if(repeats==merge_vars.size())
463  return dom;
464  }
465 
466  throw "variable live ranges with no common dominator?";
467 }
468 
478  local_variable_with_holest &merge_into,
479  const std::set<local_variable_with_holest *> &merge_vars,
480  unsigned expanded_live_range_start)
481 {
482  std::vector<local_variable_with_holest *> sorted_by_startpc(
483  merge_vars.begin(), merge_vars.end());
484  std::sort(sorted_by_startpc.begin(), sorted_by_startpc.end(), lt_startpc);
485 
487  merge_into,
488  expanded_live_range_start,
489  sorted_by_startpc[0]->var.start_pc);
490  for(std::size_t idx=0; idx<sorted_by_startpc.size()-1; ++idx)
491  {
493  merge_into,
494  sorted_by_startpc[idx]->var.start_pc+sorted_by_startpc[idx]->var.length,
495  sorted_by_startpc[idx+1]->var.start_pc);
496  }
497 }
498 
507  local_variable_with_holest &merge_into,
508  const std::set<local_variable_with_holest *> &merge_vars,
509  const java_cfg_dominatorst &dominator_analysis,
510  std::ostream &debug_out)
511 {
512  // Because we need a lexically-scoped declaration,
513  // we must have the merged variable
514  // enter scope both in a block that dominates all entries, and which
515  // precedes them in program order.
516  unsigned found_dominator=
517  get_common_dominator(merge_vars, dominator_analysis);
518 
519  // Populate the holes in the live range
520  // (addresses where the new variable will be in scope,
521  // but references to this stack slot should not resolve to it
522  // as it was not visible in the original local variable table)
523  populate_live_range_holes(merge_into, merge_vars, found_dominator);
524 
525  unsigned last_pc=0;
526  for(auto v : merge_vars)
527  {
528  if(v->var.start_pc+v->var.length>last_pc)
529  last_pc=v->var.start_pc+v->var.length;
530  }
531 
532  // Apply the changes:
533  merge_into.var.start_pc=found_dominator;
534  merge_into.var.length=last_pc-found_dominator;
535 
536 #ifdef DEBUG
537  debug_out << "Merged " << merge_vars.size() << " variables named "
538  << merge_into.var.name << "; new live range "
539  << merge_into.var.start_pc << '-'
540  << merge_into.var.start_pc + merge_into.var.length << '\n';
541 #endif
542 
543  // Nuke the now-subsumed var-table entries:
544  for(auto &v : merge_vars)
545  if(v!=&merge_into)
546  v->var.length=0;
547 }
548 
561  local_variable_table_with_holest::iterator firstvar,
562  local_variable_table_with_holest::iterator varlimit,
563  const address_mapt &amap,
564  const java_cfg_dominatorst &dominator_analysis)
565 {
566  // Build a simple map from instruction PC to the variable
567  // live in this slot at that PC, and a map from each variable
568  // to variables that flow into it:
569  std::vector<local_variable_with_holest *> live_variable_at_address;
570  populate_variable_address_map(firstvar, varlimit, live_variable_at_address);
571 
572  // Now find variables that flow together by
573  // walking backwards to find initializers
574  // or branches from other live ranges:
575  predecessor_mapt predecessor_map;
577  firstvar,
578  varlimit,
579  live_variable_at_address,
580  amap,
581  predecessor_map,
583 
584  // OK, we've established the flows all seem sensible.
585  // Now merge vartable entries according to the predecessor_map:
586 
587  // Take the transitive closure of the predecessor map:
588  for(auto &kv : predecessor_map)
589  {
590  std::set<local_variable_with_holest *> closed_preds;
591  gather_transitive_predecessors(kv.first, predecessor_map, closed_preds);
592  kv.second=std::move(closed_preds);
593  }
594 
595  // Top-sort so that we get the bottom variables first:
596  is_predecessor_oft comp(predecessor_map);
597  std::vector<local_variable_with_holest *> topsorted_vars;
598  for(auto it=firstvar, itend=varlimit; it!=itend; ++it)
599  topsorted_vars.push_back(&*it);
600 
601  std::sort(topsorted_vars.begin(), topsorted_vars.end(), comp);
602 
603  // Now merge the entries:
604  for(auto merge_into : topsorted_vars)
605  {
606  // Already merged into another variable?
607  if(merge_into->var.length==0)
608  continue;
609 
610  auto findit=predecessor_map.find(merge_into);
611  // Nothing to do?
612  if(findit==predecessor_map.end())
613  continue;
614 
615  const auto &merge_vars=findit->second;
616  INVARIANT(merge_vars.size()>=2, "merging requires at least 2 variables");
617 
619  *merge_into,
620  merge_vars,
621  dominator_analysis,
622  status());
623  }
624 }
625 
633 static void walk_to_next_index(
634  local_variable_table_with_holest::iterator &it1,
635  local_variable_table_with_holest::iterator &it2,
636  local_variable_table_with_holest::iterator itend)
637 {
638  if(it2==itend)
639  {
640  it1=itend;
641  return;
642  }
643 
644  auto old_it2=it2;
645  auto index=it2->var.index;
646  while(it2!=itend && it2->var.index==index)
647  ++it2;
648  it1=old_it2;
649 }
650 
659  const address_mapt &amap,
660  const java_cfg_dominatorst &dominator_analysis)
661 {
662  // Sort table entries by local slot index:
663  std::sort(vars.begin(), vars.end(), lt_index);
664 
665  // For each block of entries using a particular index,
666  // try to combine them:
667  auto it1=vars.begin();
668  auto it2=it1;
669  auto itend=vars.end();
670  walk_to_next_index(it1, it2, itend);
671  for(; it1!=itend; walk_to_next_index(it1, it2, itend))
672  find_initializers_for_slot(it1, it2, amap, dominator_analysis);
673 }
674 
678 static void cleanup_var_table(
679  std::vector<local_variable_with_holest> &vars_with_holes)
680 {
681  size_t toremove=0;
682  for(size_t i=0; i<(vars_with_holes.size()-toremove); ++i)
683  {
684  auto &v=vars_with_holes[i];
685  if(v.var.length==0)
686  {
687  // Move to end; consider the new element we've swapped in:
688  ++toremove;
689  if(i!=vars_with_holes.size()-toremove) // Already where it needs to be?
690  std::swap(v, vars_with_holes[vars_with_holes.size()-toremove]);
691  --i; // May make i (size_t)-1, but it will immediately be
692  // re-incremented as the loop iterates.
693  }
694  }
695 
696  // Remove un-needed entries.
697  vars_with_holes.resize(vars_with_holes.size()-toremove);
698 }
699 
707  const methodt &m,
708  const address_mapt &amap)
709 {
710  // Compute CFG dominator tree
711  java_cfg_dominatorst dominator_analysis;
712  method_with_amapt dominator_args(m, amap);
713  dominator_analysis(dominator_args);
714 
715 #ifdef DEBUG
716  debug() << "jcm: setup-local-vars: m.is_static "
717  << m.is_static << " m.descriptor " << m.descriptor << eom;
718  debug() << "jcm: setup-local-vars: lv arg slots "
720  debug() << "jcm: setup-local-vars: lvt size "
721  << m.local_variable_table.size() << eom;
722 #endif
723 
724  // Find out which local variable table entries should be merged:
725  // Wrap each entry so we have a data structure to work during function calls,
726  // where we record live ranges with holes:
727  std::vector<local_variable_with_holest> vars_with_holes;
728  for(const auto &v : m.local_variable_table)
729  vars_with_holes.push_back({v, is_parameter(v), {}});
730 
731  // Merge variable records. See documentation of in
732  // `find_initializers_for_slot` for more details. If the strategy employed
733  // there fails with an exception, we just ignore the LVT for this method, no
734  // variable is generated in `this->variables[]` (because we return here and
735  // dont let the for loop below to execute), and as a result the method
736  // this->variable() will be forced to create new `anonlocal::` variables, as
737  // the only source of variable names for that method is `this->variables[]`.
738  try
739  {
740  find_initializers(vars_with_holes, amap, dominator_analysis);
741  }
742  catch(const char *message)
743  {
744  warning() << "Bytecode -> codet translation error: " << message << eom
745  << "This is probably due to an unexpected LVT, "
746  << "falling back to translation without LVT" << eom;
747  return;
748  }
749 
750  // Clean up removed records from the variable table:
751  cleanup_var_table(vars_with_holes);
752 
753  // Do the locals and parameters in the variable table, which is available when
754  // compiled with -g or for methods with many local variables in the latter
755  // case, different variables can have the same index, depending on the
756  // context.
757  //
758  // to calculate which variable to use, one uses the address of the instruction
759  // that uses the variable, the size of the instruction and the start_pc /
760  // length values in the local variable table
761  for(const auto &v : vars_with_holes)
762  {
763  if(v.is_parameter)
764  continue;
765 
766 #ifdef DEBUG
767  debug() << "jcm: setup-local-vars: merged variable: idx " << v.var.index
768  << " name " << v.var.name << " v.var.descriptor '"
769  << v.var.descriptor << "' holes " << v.holes.size() << eom;
770 #endif
771  typet t;
772  // TODO: might need changing once descriptor/signature issue is resolved
773  t=java_type_from_string(v.var.descriptor);
774 
775  std::ostringstream id_oss;
776  id_oss << method_id << "::" << v.var.start_pc << "::" << v.var.name;
777  irep_idt identifier(id_oss.str());
778  symbol_exprt result(identifier, t);
779  result.set(ID_C_base_name, v.var.name);
780 
781  // Create a new local variable in the variables[] array, the result of
782  // merging multiple local variables with equal name (parameters excluded)
783  // into a single local variable with holes
784  variables[v.var.index].push_back(variablet());
785  auto &newv=variables[v.var.index].back();
786  newv.symbol_expr=result;
787  newv.start_pc=v.var.start_pc;
788  newv.length=v.var.length;
789  newv.holes=std::move(v.holes);
790 
791  // Register the local variable in the symbol table
792  symbolt new_symbol;
793  new_symbol.name=identifier;
794  new_symbol.type=t;
795  new_symbol.base_name=v.var.name;
796  new_symbol.pretty_name=id2string(identifier).substr(6, std::string::npos);
797  new_symbol.mode=ID_java;
798  new_symbol.is_type=false;
799  new_symbol.is_file_local=true;
800  new_symbol.is_thread_local=true;
801  new_symbol.is_lvalue=true;
802  symbol_table.add(new_symbol);
803  }
804 }
805 
814  size_t address,
815  variablest &var_list)
816 {
817  for(const variablet &var : var_list)
818  {
819  size_t start_pc=var.start_pc;
820  size_t length=var.length;
821  if(address>=start_pc && address<(start_pc+length))
822  {
823  bool found_hole=false;
824  for(auto &hole : var.holes)
825  if(address>=hole.start_pc && address<(hole.start_pc+hole.length))
826  {
827  found_hole=true;
828  break;
829  }
830  if(found_hole)
831  continue;
832  return var;
833  }
834  }
835  // add unnamed local variable to end of list at this index
836  // with scope from 0 to SIZE_T_MAX
837  // as it is at the end of the vector, it will only be taken into account
838  // if no other variable is valid
839  size_t list_length=var_list.size();
840  var_list.resize(list_length+1);
841  var_list[list_length].start_pc=0;
842  var_list[list_length].length=std::numeric_limits<size_t>::max();
843  return var_list[list_length];
844 }
The type of an expression.
Definition: type.h:22
irep_idt name
The unique identifier.
Definition: symbol.h:43
static void merge_variable_table_entries(local_variable_with_holest &merge_into, const std::set< local_variable_with_holest *> &merge_vars, const java_cfg_dominatorst &dominator_analysis, std::ostream &debug_out)
See above.
java_bytecode_convert_methodt::address_mapt address_mapt
A generic directed graph with a parametric node type.
Definition: graph.h:133
JAVA Bytecode Language Conversion.
const std::string & id2string(const irep_idt &d)
Definition: irep.h:43
bool is_thread_local
Definition: symbol.h:67
void find_initializers(local_variable_table_with_holest &vars, const address_mapt &amap, const java_cfg_dominatorst &doms)
See find_initializers_for_slot above for more detail.
std::pair< const methodt &, const address_mapt & > method_with_amapt
irep_idt method_id
Fully qualified name of the method under translation.
irep_idt mode
Language mode.
Definition: symbol.h:52
entry_mapt entry_map
Definition: cfg.h:106
static void maybe_add_hole(local_variable_with_holest &var, unsigned from, unsigned to)
See above.
static unsigned get_common_dominator(const std::set< local_variable_with_holest *> &merge_vars, const java_cfg_dominatorst &dominator_analysis)
Used to find out where to put a variable declaration that subsumes several variable live ranges...
void setup_local_variables(const methodt &m, const address_mapt &amap)
See find_initializers_for_slot above for more detail.
irep_idt pretty_name
Language-specific display name.
Definition: symbol.h:55
Symbol table entry.This is a symbol in the symbol table, stored in an object of type symbol_tablet...
Definition: symbol.h:30
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:245
static mstreamt & eom(mstreamt &m)
Definition: message.h:272
bool is_parameter(const local_variablet &v)
Returns true iff the slot index of the local variable of a method (coming from the LVT) is a paramete...
std::map< unsigned, converted_instructiont > address_mapt
static bool is_store_to_slot(const java_bytecode_convert_methodt::instructiont &inst, unsigned slotidx)
See above.
#define INVARIANT(CONDITION, REASON)
Definition: invariant.h:205
mstreamt & warning() const
Definition: message.h:307
bool to_unsigned_integer(const constant_exprt &expr, unsigned &uint_value)
convert a positive integer expression to an unsigned int
Definition: arith_tools.cpp:94
std::vector< local_variable_with_holest > local_variable_table_with_holest
typet java_type_from_string(const std::string &src, const std::string &class_name_prefix)
Transforms a string representation of a Java type into an internal type representation thereof...
Definition: java_types.cpp:428
static void walk_to_next_index(local_variable_table_with_holest::iterator &it1, local_variable_table_with_holest::iterator &it2, local_variable_table_with_holest::iterator itend)
Walk a vector, a contiguous block of entries with equal slot index at a time.
java_bytecode_convert_methodt::holet holet
static void gather_transitive_predecessors(local_variable_with_holest *start, const predecessor_mapt &predecessor_map, std::set< local_variable_with_holest *> &result)
See above start: Variable to find the predecessors of predecessor_map: Map from local variables to se...
static void populate_live_range_holes(local_variable_with_holest &merge_into, const std::set< local_variable_with_holest *> &merge_vars, unsigned expanded_live_range_start)
See above.
std::map< local_variable_with_holest *, std::set< local_variable_with_holest * > > predecessor_mapt
#define PRECONDITION(CONDITION)
Definition: invariant.h:230
static bool lt_startpc(const local_variable_with_holest *a, const local_variable_with_holest *b)
const constant_exprt & to_constant_expr(const exprt &expr)
Cast a generic exprt to a constant_exprt.
Definition: std_expr.h:4465
static void populate_variable_address_map(local_variable_table_with_holest::iterator firstvar, local_variable_table_with_holest::iterator varlimit, std::vector< local_variable_with_holest *> &live_variable_at_address)
See above.
java_bytecode_convert_methodt::local_variable_with_holest local_variable_with_holest
unsigned safe_string2unsigned(const std::string &str, int base)
Definition: string2int.cpp:54
java_bytecode_convert_methodt::java_cfg_dominatorst java_cfg_dominatorst
typet type
Type of symbol.
Definition: symbol.h:34
message_handlert & get_message_handler()
Definition: message.h:153
static void cleanup_var_table(std::vector< local_variable_with_holest > &vars_with_holes)
See above.
bool operator()(local_variable_with_holest *a, local_variable_with_holest *b) const
mstreamt & result() const
Definition: message.h:312
mstreamt & status() const
Definition: message.h:317
irep_idt base_name
Base (non-scoped) name.
Definition: symbol.h:49
const variablet & find_variable_for_slot(size_t address, variablest &var_list)
See above.
void add_edge(node_indext a, node_indext b)
Definition: graph.h:198
bool is_file_local
Definition: symbol.h:68
void find_initializers_for_slot(local_variable_table_with_holest::iterator firstvar, local_variable_table_with_holest::iterator varlimit, const address_mapt &amap, const java_cfg_dominatorst &doms)
Given a sequence of users of the same local variable slot, this figures out which ones are related by...
Expression to hold a symbol (variable)
Definition: std_expr.h:90
static bool lt_index(const local_variable_with_holest &a, const local_variable_with_holest &b)
bool add(const symbolt &symbol)
Add a new symbol to the symbol table.
is_predecessor_oft(const predecessor_mapt &_order)
mstreamt & debug() const
Definition: message.h:332
unsigned slots_for_parameters
Number of local variable slots used by the JVM to pass parameters upon invocation of the method under...
bool is_type
Definition: symbol.h:63
static void populate_predecessor_map(local_variable_table_with_holest::iterator firstvar, local_variable_table_with_holest::iterator varlimit, const std::vector< local_variable_with_holest *> &live_variable_at_address, const address_mapt &amap, predecessor_mapt &predecessor_map, message_handlert &msg_handler)
Populates the predecessor_map with a graph from local variable table entries to their predecessors (t...
java_bytecode_convert_methodt::local_variable_table_with_holest local_variable_table_with_holest
void push_back(const T &t)
bool is_lvalue
Definition: symbol.h:68
const predecessor_mapt & order