Skip to content

Commit 04a0ca5

Browse files
committed
Convert Java methods only when they have a caller.
1 parent 63f192c commit 04a0ca5

8 files changed

+178
-20
lines changed

src/java_bytecode/java_bytecode_convert_class.cpp

+20-7
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ class java_bytecode_convert_classt:public messaget
2828
symbol_tablet &_symbol_table,
2929
message_handlert &_message_handler,
3030
const bool &_disable_runtime_checks,
31-
int _max_array_length):
31+
int _max_array_length,
32+
lazy_methodst& _lm):
3233
messaget(_message_handler),
3334
symbol_table(_symbol_table),
3435
disable_runtime_checks(_disable_runtime_checks),
35-
max_array_length(_max_array_length)
36+
max_array_length(_max_array_length),
37+
lazy_methods(_lm)
3638
{
3739
}
3840

@@ -53,6 +55,7 @@ class java_bytecode_convert_classt:public messaget
5355
symbol_tablet &symbol_table;
5456
const bool &disable_runtime_checks;
5557
int max_array_length;
58+
lazy_methodst &lazy_methods;
5659

5760
// conversion
5861
void convert(const classt &c);
@@ -134,10 +137,18 @@ void java_bytecode_convert_classt::convert(const classt &c)
134137
convert(*class_symbol, it);
135138

136139
// now do methods
140+
137141
for(const auto & it : c.methods)
138-
java_bytecode_convert_method(
139-
*class_symbol, it, symbol_table, get_message_handler(),
140-
disable_runtime_checks, max_array_length);
142+
{
143+
const irep_idt method_identifier=
144+
id2string(qualified_classname)+"."+id2string(it.name)+":"+it.signature;
145+
java_bytecode_convert_method_lazy(
146+
*class_symbol,method_identifier,it,symbol_table);
147+
lazy_methods[method_identifier]=std::make_pair(class_symbol,&it);
148+
}
149+
//java_bytecode_convert_method(
150+
// *class_symbol, it, symbol_table, get_message_handler(),
151+
// disable_runtime_checks, max_array_length);
141152

142153
// is this a root class?
143154
if(c.extends.empty())
@@ -317,13 +328,15 @@ bool java_bytecode_convert_class(
317328
const bool &disable_runtime_checks,
318329
symbol_tablet &symbol_table,
319330
message_handlert &message_handler,
320-
int max_array_length)
331+
int max_array_length,
332+
lazy_methodst& lazy_methods)
321333
{
322334
java_bytecode_convert_classt java_bytecode_convert_class(
323335
symbol_table,
324336
message_handler,
325337
disable_runtime_checks,
326-
max_array_length);
338+
max_array_length,
339+
lazy_methods);
327340

328341
try
329342
{

src/java_bytecode/java_bytecode_convert_class.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@ Author: Daniel Kroening, [email protected]
1414

1515
#include "java_bytecode_parse_tree.h"
1616

17+
typedef std::map<irep_idt, std::pair<const symbolt*, const java_bytecode_parse_treet::methodt*> >
18+
lazy_methodst;
19+
1720
bool java_bytecode_convert_class(
1821
const java_bytecode_parse_treet &parse_tree,
1922
const bool &disable_runtime_checks,
2023
symbol_tablet &symbol_table,
2124
message_handlert &message_handler,
22-
int max_array_length);
25+
int max_array_length,
26+
lazy_methodst&);
2327

2428
#endif
2529

src/java_bytecode/java_bytecode_convert_method.cpp

+57-6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Author: Daniel Kroening, [email protected]
2020
#include <util/expr_util.h>
2121

2222
#include <goto-programs/cfg.h>
23+
#include <goto-programs/class_hierarchy.h>
2324
#include <analyses/cfg_dominators.h>
2425

2526
#include "java_bytecode_convert_method.h"
@@ -91,11 +92,15 @@ java_bytecode_convert_methodt::java_bytecode_convert_methodt(
9192
symbol_tablet &_symbol_table,
9293
message_handlert &_message_handler,
9394
const bool &_disable_runtime_checks,
94-
int _max_array_length):
95+
int _max_array_length,
96+
std::vector<irep_idt>& _needed_methods,
97+
const class_hierarchyt& _ch) :
9598
messaget(_message_handler),
9699
symbol_table(_symbol_table),
97100
disable_runtime_checks(_disable_runtime_checks),
98-
max_array_length(_max_array_length)
101+
max_array_length(_max_array_length),
102+
needed_methods(_needed_methods),
103+
class_hierarchy(_ch)
99104
{
100105
}
101106

@@ -181,6 +186,35 @@ void java_bytecode_convert_methodt::push(const exprt::operandst &o)
181186
stack[stack.size()-o.size()+i]=o[i];
182187
}
183188

189+
void java_bytecode_convert_method_lazy(
190+
const symbolt& class_symbol,
191+
const irep_idt method_identifier,
192+
const java_bytecode_parse_treet::methodt &m,
193+
symbol_tablet& symbol_table)
194+
{
195+
symbolt method_symbol;
196+
typet member_type=java_type_from_string(m.signature);
197+
198+
method_symbol.name=method_identifier;
199+
method_symbol.base_name=m.base_name;
200+
method_symbol.mode=ID_java;
201+
method_symbol.location=m.source_location;
202+
method_symbol.location.set_function(method_identifier);
203+
204+
if(method_symbol.base_name=="<init>")
205+
{
206+
method_symbol.pretty_name=id2string(class_symbol.pretty_name)+"."+
207+
id2string(class_symbol.base_name)+"()";
208+
member_type.set(ID_constructor,true);
209+
}
210+
else
211+
method_symbol.pretty_name=id2string(class_symbol.pretty_name)+"."+
212+
id2string(m.base_name)+"()";
213+
214+
method_symbol.type=member_type;
215+
symbol_table.add(method_symbol);
216+
}
217+
184218
/*******************************************************************\
185219
186220
Function: java_bytecode_convert_methodt::convert
@@ -346,9 +380,9 @@ void java_bytecode_convert_methodt::convert(
346380
if(!m.is_abstract)
347381
method_symbol.value=convert_instructions(m, code_type);
348382

349-
// do we have the method symbol already?
383+
// Replace the existing stub symbol with the real deal:
350384
const auto s_it=symbol_table.symbols.find(method.get_name());
351-
if(s_it!=symbol_table.symbols.end())
385+
assert(s_it!=symbol_table.symbols.end());
352386
symbol_table.symbols.erase(s_it); // erase, we stubbed it
353387

354388
symbol_table.add(method_symbol);
@@ -991,13 +1025,26 @@ codet java_bytecode_convert_methodt::convert_instructions(
9911025
id2string(fn_basename) + "()";
9921026
auto fn_type=arg0.type();
9931027
check_stub_function(id,fn_basename,fn_prettyname,fn_type);
1028+
1029+
needed_methods.push_back(arg0.get(ID_identifier));
9941030

9951031
if(is_virtual)
9961032
{
9971033
// dynamic binding
9981034
assert(use_this);
9991035
assert(!call.arguments().empty());
10001036
call.function()=arg0;
1037+
const auto& call_class=arg0.get(ID_C_class);
1038+
assert(call_class!=irep_idt());
1039+
const auto& call_basename=arg0.get(ID_component_name);
1040+
assert(call_basename!=irep_idt());
1041+
auto child_classes=class_hierarchy.get_children_trans(call_class);
1042+
for(const auto& child_class : child_classes)
1043+
{
1044+
auto methodid=id2string(child_class)+"."+id2string(call_basename);
1045+
if(symbol_table.has_symbol(methodid))
1046+
needed_methods.push_back(methodid);
1047+
}
10011048
}
10021049
else
10031050
{
@@ -1974,13 +2021,17 @@ void java_bytecode_convert_method(
19742021
symbol_tablet &symbol_table,
19752022
message_handlert &message_handler,
19762023
const bool &disable_runtime_checks,
1977-
int max_array_length)
2024+
int max_array_length,
2025+
std::vector<irep_idt>& needed_methods,
2026+
const class_hierarchyt& ch)
19782027
{
19792028
java_bytecode_convert_methodt java_bytecode_convert_method(
19802029
symbol_table,
19812030
message_handler,
19822031
disable_runtime_checks,
1983-
max_array_length);
2032+
max_array_length,
2033+
needed_methods,
2034+
ch);
19842035

19852036
java_bytecode_convert_method(class_symbol, method);
19862037
}

src/java_bytecode/java_bytecode_convert_method.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,23 @@ Author: Daniel Kroening, [email protected]
1414

1515
#include "java_bytecode_parse_tree.h"
1616

17+
class class_hierarchyt;
18+
1719
void java_bytecode_convert_method(
1820
const symbolt &class_symbol,
1921
const java_bytecode_parse_treet::methodt &,
2022
symbol_tablet &symbol_table,
2123
message_handlert &message_handler,
2224
const bool &enable_runtime_checks,
23-
int max_array_length);
25+
int max_array_length,
26+
std::vector<irep_idt>& needed_methods,
27+
const class_hierarchyt&);
28+
29+
void java_bytecode_convert_method_lazy(
30+
const symbolt &class_symbol,
31+
const irep_idt method_identifier,
32+
const java_bytecode_parse_treet::methodt &,
33+
symbol_tablet &symbol_table);
2434

2535
#endif
2636

src/java_bytecode/java_bytecode_convert_method_class.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
#include <util/std_expr.h>
99
#include <analyses/cfg_dominators.h>
1010
#include "java_bytecode_parse_tree.h"
11+
#include "java_bytecode_convert_class.h"
1112

1213
#include <vector>
1314
#include <list>
1415

1516
class symbol_tablet;
1617
class symbolt;
18+
class class_hierarchyt;
1719

1820
class java_bytecode_convert_methodt:public messaget
1921
{
@@ -22,7 +24,9 @@ class java_bytecode_convert_methodt:public messaget
2224
symbol_tablet &_symbol_table,
2325
message_handlert &_message_handler,
2426
const bool &_disable_runtime_checks,
25-
int _max_array_length);
27+
int _max_array_length,
28+
std::vector<irep_idt>& _needed_methods,
29+
const class_hierarchyt& _ch);
2630

2731
typedef java_bytecode_parse_treet::methodt methodt;
2832
typedef java_bytecode_parse_treet::instructiont instructiont;
@@ -53,6 +57,8 @@ class java_bytecode_convert_methodt:public messaget
5357
symbol_tablet &symbol_table;
5458
const bool &disable_runtime_checks;
5559
int max_array_length;
60+
std::vector<irep_idt>& needed_methods;
61+
const class_hierarchyt& class_hierarchy;
5662

5763
irep_idt current_method;
5864
typet method_return_type;

src/java_bytecode/java_bytecode_language.cpp

+73-1
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@ Author: Daniel Kroening, [email protected]
1212
#include <util/cmdline.h>
1313
#include <util/string2int.h>
1414

15+
#include <goto-programs/class_hierarchy.h>
16+
1517
#include "java_bytecode_language.h"
1618
#include "java_bytecode_convert_class.h"
19+
#include "java_bytecode_convert_method.h"
1720
#include "java_bytecode_internal_additions.h"
1821
#include "java_bytecode_typecheck.h"
1922
#include "java_entry_point.h"
@@ -181,10 +184,15 @@ Function: java_bytecode_languaget::typecheck
181184
182185
\*******************************************************************/
183186

187+
188+
184189
bool java_bytecode_languaget::typecheck(
185190
symbol_tablet &symbol_table,
186191
const std::string &module)
187192
{
193+
std::map<irep_idt, std::pair<const symbolt*, const java_bytecode_parse_treet::methodt*> >
194+
lazy_methods;
195+
188196
// first convert all
189197
for(java_class_loadert::class_mapt::const_iterator
190198
c_it=java_class_loader.class_map.begin();
@@ -201,10 +209,74 @@ bool java_bytecode_languaget::typecheck(
201209
disable_runtime_checks,
202210
symbol_table,
203211
get_message_handler(),
204-
max_user_array_length))
212+
max_user_array_length,
213+
lazy_methods
214+
))
205215
return true;
206216
}
207217

218+
// Now incrementally elaborate methods that are reachable from this entry point:
219+
220+
// Convert-method will need this to find virtual function targets.
221+
class_hierarchyt ch;
222+
ch(symbol_table);
223+
224+
std::vector<irep_idt> worklist1;
225+
std::vector<irep_idt> worklist2;
226+
227+
auto main_function=get_main_symbol(symbol_table,main_class,get_message_handler(),true);
228+
if(std::get<2>(main_function))
229+
{
230+
// Failed, mark all functions in the given main class reachable.
231+
const auto& methods=java_class_loader.class_map.at(main_class).parsed_class.methods;
232+
for(const auto& method : methods)
233+
{
234+
const irep_idt methodid="java::"+id2string(main_class)+"."+
235+
id2string(method.name)+":"+
236+
id2string(method.signature);
237+
worklist2.push_back(methodid);
238+
}
239+
}
240+
else
241+
worklist2.push_back(std::get<0>(main_function).name);
242+
243+
std::set<irep_idt> already_populated;
244+
while(worklist2.size()!=0)
245+
{
246+
std::swap(worklist1,worklist2);
247+
for(const auto& mname : worklist1)
248+
{
249+
if(!already_populated.insert(mname).second)
250+
continue;
251+
auto findit=lazy_methods.find(mname);
252+
if(findit==lazy_methods.end())
253+
{
254+
debug() << "Skip " << mname << eom;
255+
continue;
256+
}
257+
debug() << "Lazy methods: elaborate " << mname << eom;
258+
const auto& parsed_method=findit->second;
259+
java_bytecode_convert_method(*parsed_method.first,*parsed_method.second,
260+
symbol_table,get_message_handler(),
261+
disable_runtime_checks,max_user_array_length,worklist2,ch);
262+
}
263+
worklist1.clear();
264+
}
265+
266+
// Remove symbols for methods that were declared but never used:
267+
symbol_tablet keep_symbols;
268+
269+
for(const auto& sym : symbol_table.symbols)
270+
{
271+
if(lazy_methods.count(sym.first) && !already_populated.count(sym.first))
272+
continue;
273+
keep_symbols.add(sym.second);
274+
}
275+
276+
debug() << "Lazy methods: removed " << symbol_table.symbols.size() - keep_symbols.symbols.size() << " unreachable methods" << eom;
277+
278+
symbol_table.swap(keep_symbols);
279+
208280
// now typecheck all
209281
if(java_bytecode_typecheck(
210282
symbol_table, get_message_handler()))

src/java_bytecode/java_entry_point.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,8 @@ void java_record_outputs(
327327

328328
std::tuple<symbolt, bool, bool> get_main_symbol(symbol_tablet &symbol_table,
329329
const irep_idt &main_class,
330-
message_handlert &message_handler)
330+
message_handlert &message_handler,
331+
bool allow_no_body)
331332
{
332333
symbolt symbol;
333334

@@ -449,7 +450,7 @@ std::tuple<symbolt, bool, bool> get_main_symbol(symbol_tablet &symbol_table,
449450
symbol=symbol_table.symbols.find(*matches.begin())->second;
450451

451452
// check if it has a body
452-
if(symbol.value.is_nil())
453+
if(symbol.value.is_nil() && !allow_no_body)
453454
{
454455
message.error() << "main method `" << main_class
455456
<< "' has no body" << messaget::eom;

src/java_bytecode/java_entry_point.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ bool java_entry_point(
2222

2323
std::tuple<symbolt, bool, bool> get_main_symbol(symbol_tablet &symbol_table,
2424
const irep_idt &main_class,
25-
message_handlert &);
25+
message_handlert &,
26+
bool allow_no_body = false);
2627

2728
#endif

0 commit comments

Comments
 (0)