Skip to content

Commit d627638

Browse files
Extract convert_invoke function
1 parent fcfca08 commit d627638

File tree

2 files changed

+176
-163
lines changed

2 files changed

+176
-163
lines changed

jbmc/src/java_bytecode/java_bytecode_convert_method.cpp

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

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

jbmc/src/java_bytecode/java_bytecode_convert_method_class.h

+7
Original file line numberDiff line numberDiff line change
@@ -444,5 +444,12 @@ class java_bytecode_convert_methodt:public messaget
444444
exprt::operandst &results) const;
445445

446446
codet &replace_call_to_cprover_assume(source_locationt location, codet &c);
447+
448+
void convert_invoke(
449+
source_locationt location,
450+
const irep_idt &statement,
451+
exprt &arg0,
452+
codet &c,
453+
exprt::operandst &results);
447454
};
448455
#endif

0 commit comments

Comments
 (0)