Skip to content

Commit 5480592

Browse files
Extract convert_invoke function
1 parent f1d3aee commit 5480592

File tree

2 files changed

+179
-163
lines changed

2 files changed

+179
-163
lines changed

src/java_bytecode/java_bytecode_convert_method.cpp

+171-163
Original file line numberDiff line numberDiff line change
@@ -1214,169 +1214,7 @@ codet java_bytecode_convert_methodt::convert_instructions(
12141214
statement=="invokevirtual" ||
12151215
statement=="invokestatic")
12161216
{
1217-
const bool use_this(statement!="invokestatic");
1218-
const bool is_virtual(
1219-
statement=="invokevirtual" || statement=="invokeinterface");
1220-
1221-
code_typet &code_type=to_code_type(arg0.type());
1222-
code_typet::parameterst &parameters(code_type.parameters());
1223-
1224-
if(use_this)
1225-
{
1226-
if(parameters.empty() || !parameters[0].get_this())
1227-
{
1228-
irep_idt classname=arg0.get(ID_C_class);
1229-
typet thistype=symbol_typet(classname);
1230-
// Note invokespecial is used for super-method calls as well as
1231-
// constructors.
1232-
if(statement=="invokespecial")
1233-
{
1234-
if(is_constructor(arg0.get(ID_identifier)))
1235-
{
1236-
if(needed_lazy_methods)
1237-
needed_lazy_methods->add_needed_class(classname);
1238-
code_type.set_is_constructor();
1239-
}
1240-
else
1241-
code_type.set(ID_java_super_method_call, true);
1242-
}
1243-
reference_typet object_ref_type=java_reference_type(thistype);
1244-
code_typet::parametert this_p(object_ref_type);
1245-
this_p.set_this();
1246-
this_p.set_base_name("this");
1247-
parameters.insert(parameters.begin(), this_p);
1248-
}
1249-
}
1250-
1251-
code_function_callt call;
1252-
source_locationt loc=i_it->source_location;
1253-
loc.set_function(method_id);
1254-
1255-
call.add_source_location()=loc;
1256-
call.arguments()=pop(parameters.size());
1257-
1258-
// double-check a bit
1259-
if(use_this)
1260-
{
1261-
const exprt &this_arg=call.arguments().front();
1262-
INVARIANT(this_arg.type().id()==ID_pointer,
1263-
"first argument must be a pointer");
1264-
}
1265-
1266-
// do some type adjustment for the arguments,
1267-
// as Java promotes arguments
1268-
// Also cast pointers since intermediate locals
1269-
// can be void*.
1270-
1271-
for(std::size_t i=0; i<parameters.size(); i++)
1272-
{
1273-
const typet &type=parameters[i].type();
1274-
if(type==java_boolean_type() ||
1275-
type==java_char_type() ||
1276-
type==java_byte_type() ||
1277-
type==java_short_type() ||
1278-
type.id()==ID_pointer)
1279-
{
1280-
assert(i<call.arguments().size());
1281-
if(type!=call.arguments()[i].type())
1282-
call.arguments()[i].make_typecast(type);
1283-
}
1284-
}
1285-
1286-
// do some type adjustment for return values
1287-
1288-
const typet &return_type=code_type.return_type();
1289-
1290-
if(return_type.id()!=ID_empty)
1291-
{
1292-
// return types are promoted in Java
1293-
call.lhs()=tmp_variable("return", return_type);
1294-
exprt promoted=java_bytecode_promotion(call.lhs());
1295-
results.resize(1);
1296-
results[0]=promoted;
1297-
}
1298-
1299-
assert(arg0.id()==ID_virtual_function);
1300-
1301-
// If we don't have a definition for the called symbol, and we won't
1302-
// inherit a definition from a super-class, we create a new symbol and
1303-
// insert it in the symbol table. The name and type of the method are
1304-
// derived from the information we have in the call.
1305-
// We fix the access attribute to ID_public, because of the following
1306-
// reasons:
1307-
// - We don't know the orignal access attribute and since the .class file
1308-
// unavailable, we have no way to know.
1309-
// - Whatever it was, we assume that the bytecode we are translating
1310-
// compiles correctly, so such a method has to be accessible from this
1311-
// method.
1312-
// - We will never generate code that calls that method unless we
1313-
// translate bytecode that calls that method. As a result we will never
1314-
// generate code that may wrongly assume that such a method is
1315-
// accessible if we assume that its access attribute is "more
1316-
// accessible" than it actually is.
1317-
irep_idt id=arg0.get(ID_identifier);
1318-
if(symbol_table.symbols.find(id)==symbol_table.symbols.end() &&
1319-
!(is_virtual && is_method_inherited(arg0.get(ID_C_class), arg0.get(ID_component_name))))
1320-
{
1321-
symbolt symbol;
1322-
symbol.name=id;
1323-
symbol.base_name=arg0.get(ID_C_base_name);
1324-
symbol.pretty_name=
1325-
id2string(arg0.get(ID_C_class)).substr(6)+"."+
1326-
id2string(symbol.base_name)+"()";
1327-
symbol.type=arg0.type();
1328-
symbol.type.set(ID_access, ID_public);
1329-
symbol.value.make_nil();
1330-
symbol.mode=ID_java;
1331-
assign_parameter_names(
1332-
to_code_type(symbol.type),
1333-
symbol.name,
1334-
symbol_table);
1335-
1336-
debug()
1337-
<< "Generating codet: new opaque symbol: method '"
1338-
<< symbol.name << "'" << eom;
1339-
symbol_table.add(symbol);
1340-
}
1341-
1342-
if(is_virtual)
1343-
{
1344-
// dynamic binding
1345-
assert(use_this);
1346-
assert(!call.arguments().empty());
1347-
call.function()=arg0;
1348-
// Populate needed methods later,
1349-
// once we know what object types can exist.
1350-
}
1351-
else
1352-
{
1353-
// static binding
1354-
call.function()=symbol_exprt(arg0.get(ID_identifier), arg0.type());
1355-
if(needed_lazy_methods)
1356-
{
1357-
needed_lazy_methods->add_needed_method(arg0.get(ID_identifier));
1358-
// Calling a static method causes static initialization:
1359-
needed_lazy_methods->add_needed_class(arg0.get(ID_C_class));
1360-
}
1361-
}
1362-
1363-
call.function().add_source_location()=loc;
1364-
1365-
// Replacing call if it is a function of the Character library,
1366-
// returning the same call otherwise
1367-
c=string_preprocess.replace_character_call(call);
1368-
1369-
if(!use_this)
1370-
{
1371-
codet clinit_call=get_clinit_call(arg0.get(ID_C_class));
1372-
if(clinit_call.get_statement()!=ID_skip)
1373-
{
1374-
code_blockt ret_block;
1375-
ret_block.move_to_operands(clinit_call);
1376-
ret_block.move_to_operands(c);
1377-
c=std::move(ret_block);
1378-
}
1379-
}
1217+
convert_invoke(i_it, statement, arg0, c, results);
13801218
}
13811219
else if(statement=="return")
13821220
{
@@ -2136,6 +1974,176 @@ codet java_bytecode_convert_methodt::convert_instructions(
21361974
return code;
21371975
}
21381976

1977+
void java_bytecode_convert_methodt::convert_invoke(
1978+
const std::vector<java_bytecode_parse_treet::instructiont>::const_iterator
1979+
&i_it,
1980+
const irep_idt &statement,
1981+
exprt &arg0,
1982+
codet &c,
1983+
exprt::operandst &results)
1984+
{
1985+
const bool use_this(statement != "invokestatic");
1986+
const bool is_virtual(
1987+
statement == "invokevirtual" || statement == "invokeinterface");
1988+
1989+
code_typet &code_type = to_code_type(arg0.type());
1990+
code_typet::parameterst &parameters(code_type.parameters());
1991+
1992+
if(use_this)
1993+
{
1994+
if(parameters.empty() || !parameters[0].get_this())
1995+
{
1996+
irep_idt classname = arg0.get(ID_C_class);
1997+
typet thistype = symbol_typet(classname);
1998+
// Note invokespecial is used for super-method calls as well as
1999+
// constructors.
2000+
if(statement == "invokespecial")
2001+
{
2002+
if(is_constructor(arg0.get(ID_identifier)))
2003+
{
2004+
if(needed_lazy_methods)
2005+
needed_lazy_methods->add_needed_class(classname);
2006+
code_type.set_is_constructor();
2007+
}
2008+
else
2009+
code_type.set(ID_java_super_method_call, true);
2010+
}
2011+
reference_typet object_ref_type = java_reference_type(thistype);
2012+
code_typet::parametert this_p(object_ref_type);
2013+
this_p.set_this();
2014+
this_p.set_base_name("this");
2015+
parameters.insert(parameters.begin(), this_p);
2016+
}
2017+
}
2018+
2019+
code_function_callt call;
2020+
source_locationt loc = i_it->source_location;
2021+
loc.set_function(method_id);
2022+
2023+
call.add_source_location() = loc;
2024+
call.arguments() = pop(parameters.size());
2025+
2026+
// double-check a bit
2027+
if(use_this)
2028+
{
2029+
const exprt &this_arg = call.arguments().front();
2030+
INVARIANT(
2031+
this_arg.type().id() == ID_pointer, "first argument must be a pointer");
2032+
}
2033+
2034+
// do some type adjustment for the arguments,
2035+
// as Java promotes arguments
2036+
// Also cast pointers since intermediate locals
2037+
// can be void*.
2038+
2039+
for(std::size_t i = 0; i < parameters.size(); i++)
2040+
{
2041+
const typet &type = parameters[i].type();
2042+
if(
2043+
type == java_boolean_type() || type == java_char_type() ||
2044+
type == java_byte_type() || type == java_short_type() ||
2045+
type.id() == ID_pointer)
2046+
{
2047+
assert(i < call.arguments().size());
2048+
if(type != call.arguments()[i].type())
2049+
call.arguments()[i].make_typecast(type);
2050+
}
2051+
}
2052+
2053+
// do some type adjustment for return values
2054+
2055+
const typet &return_type = code_type.return_type();
2056+
2057+
if(return_type.id() != ID_empty)
2058+
{
2059+
// return types are promoted in Java
2060+
call.lhs() = tmp_variable("return", return_type);
2061+
exprt promoted = java_bytecode_promotion(call.lhs());
2062+
results.resize(1);
2063+
results[0] = promoted;
2064+
}
2065+
2066+
assert(arg0.id() == ID_virtual_function);
2067+
2068+
// If we don't have a definition for the called symbol, and we won't
2069+
// inherit a definition from a super-class, we create a new symbol and
2070+
// insert it in the symbol table. The name and type of the method are
2071+
// derived from the information we have in the call.
2072+
// We fix the access attribute to ID_public, because of the following
2073+
// reasons:
2074+
// - We don't know the orignal access attribute and since the .class file
2075+
// unavailable, we have no way to know.
2076+
// - Whatever it was, we assume that the bytecode we are translating
2077+
// compiles correctly, so such a method has to be accessible from this
2078+
// method.
2079+
// - We will never generate code that calls that method unless we
2080+
// translate bytecode that calls that method. As a result we will never
2081+
// generate code that may wrongly assume that such a method is
2082+
// accessible if we assume that its access attribute is "more
2083+
// accessible" than it actually is.
2084+
irep_idt id = arg0.get(ID_identifier);
2085+
if(
2086+
symbol_table.symbols.find(id) == symbol_table.symbols.end() &&
2087+
!(is_virtual &&
2088+
is_method_inherited(arg0.get(ID_C_class), arg0.get(ID_component_name))))
2089+
{
2090+
symbolt symbol;
2091+
symbol.name = id;
2092+
symbol.base_name = arg0.get(ID_C_base_name);
2093+
symbol.pretty_name = id2string(arg0.get(ID_C_class)).substr(6) + "." +
2094+
id2string(symbol.base_name) + "()";
2095+
symbol.type = arg0.type();
2096+
symbol.type.set(ID_access, ID_public);
2097+
symbol.value.make_nil();
2098+
symbol.mode = ID_java;
2099+
assign_parameter_names(
2100+
to_code_type(symbol.type), symbol.name, symbol_table);
2101+
2102+
debug() << "Generating codet: new opaque symbol: method '" << symbol.name
2103+
<< "'" << eom;
2104+
symbol_table.add(symbol);
2105+
}
2106+
2107+
if(is_virtual)
2108+
{
2109+
// dynamic binding
2110+
assert(use_this);
2111+
assert(!call.arguments().empty());
2112+
call.function() = arg0;
2113+
// Populate needed methods later,
2114+
// once we know what object types can exist.
2115+
}
2116+
else
2117+
{
2118+
// static binding
2119+
call.function() = symbol_exprt(arg0.get(ID_identifier), arg0.type());
2120+
if(needed_lazy_methods)
2121+
{
2122+
needed_lazy_methods->add_needed_method(arg0.get(ID_identifier));
2123+
// Calling a static method causes static initialization:
2124+
needed_lazy_methods->add_needed_class(arg0.get(ID_C_class));
2125+
}
2126+
}
2127+
2128+
call.function().add_source_location() = loc;
2129+
2130+
// Replacing call if it is a function of the Character library,
2131+
// returning the same call otherwise
2132+
c = string_preprocess.replace_character_call(call);
2133+
2134+
if(!use_this)
2135+
{
2136+
codet clinit_call = get_clinit_call(arg0.get(ID_C_class));
2137+
if(clinit_call.get_statement() != ID_skip)
2138+
{
2139+
code_blockt ret_block;
2140+
ret_block.move_to_operands(clinit_call);
2141+
ret_block.move_to_operands(c);
2142+
c = std::move(ret_block);
2143+
}
2144+
}
2145+
}
2146+
21392147
codet &java_bytecode_convert_methodt::replace_call_to_cprover_assume(
21402148
const std::vector<java_bytecode_parse_treet::instructiont>::const_iterator
21412149
&i_it,

src/java_bytecode/java_bytecode_convert_method_class.h

+8
Original file line numberDiff line numberDiff line change
@@ -441,5 +441,13 @@ class java_bytecode_convert_methodt:public messaget
441441
const std::vector<java_bytecode_parse_treet::instructiont>::const_iterator
442442
&i_it,
443443
codet &c);
444+
445+
void convert_invoke(
446+
const std::vector<java_bytecode_parse_treet::instructiont>::const_iterator
447+
&i_it,
448+
const irep_idt &statement,
449+
exprt &arg0,
450+
codet &c,
451+
exprt::operandst &results);
444452
};
445453
#endif

0 commit comments

Comments
 (0)